diff options
author | William McKinnon <[email protected]> | 2024-10-25 11:14:37 -0400 |
---|---|---|
committer | GitHub <[email protected]> | 2024-10-25 11:14:37 -0400 |
commit | d998099612f0397234910ce753859ee127ec5b45 (patch) | |
tree | e60d699901f14054ea44718b1be8fcaf7dc9f244 /types | |
parent | be5a78ac298f3b23c9955022ad35a18180a5894a (diff) |
feat: add shadow_node (#66)
---------
Co-authored-by: Erik Reider <[email protected]>
Diffstat (limited to 'types')
-rw-r--r-- | types/fx/meson.build | 1 | ||||
-rw-r--r-- | types/fx/shadow_data.c | 15 | ||||
-rw-r--r-- | types/scene/wlr_scene.c | 260 |
3 files changed, 192 insertions, 84 deletions
diff --git a/types/fx/meson.build b/types/fx/meson.build index 3932965..d8bef8c 100644 --- a/types/fx/meson.build +++ b/types/fx/meson.build @@ -1,4 +1,3 @@ scenefx_files += files( - 'shadow_data.c', 'blur_data.c', ) diff --git a/types/fx/shadow_data.c b/types/fx/shadow_data.c deleted file mode 100644 index d74cadc..0000000 --- a/types/fx/shadow_data.c +++ /dev/null @@ -1,15 +0,0 @@ -#include "scenefx/types/fx/shadow_data.h" - -struct shadow_data shadow_data_get_default(void) { - return (struct shadow_data) { - .blur_sigma = 20, - .color = {0.0f, 0.0f, 0.0f, 0.5f}, - .enabled = false, - .offset_x = 0.0f, - .offset_y = 0.0f, - }; -} - -bool scene_buffer_has_shadow(struct shadow_data *data) { - return data->enabled && data->blur_sigma > 0 && data->color.a > 0.0; -} diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 2f4dd45..e5d4f39 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -2,7 +2,6 @@ #include <assert.h> #include <pixman.h> #include <stdlib.h> -#include <scenefx/types/fx/shadow_data.h> #include <scenefx/types/wlr_scene.h> #include <string.h> #include <wlr/backend.h> @@ -18,7 +17,6 @@ #include <wlr/render/swapchain.h> #include "scenefx/render/pass.h" -#include "scenefx/types/fx/shadow_data.h" #include "types/wlr_buffer.h" #include "types/wlr_output.h" #include "types/wlr_scene.h" @@ -47,6 +45,12 @@ struct wlr_scene_buffer *wlr_scene_buffer_from_node( return buffer; } +struct wlr_scene_shadow *wlr_scene_shadow_from_node(struct wlr_scene_node *node) { + assert(node->type == WLR_SCENE_NODE_SHADOW); + struct wlr_scene_shadow *shadow = wl_container_of(node, shadow, node); + return shadow; +} + struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { struct wlr_scene_tree *tree; if (node->type == WLR_SCENE_NODE_TREE) { @@ -214,6 +218,7 @@ static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box } break; case WLR_SCENE_NODE_RECT: + case WLR_SCENE_NODE_SHADOW: case WLR_SCENE_NODE_BUFFER:; struct wlr_box node_box = { .x = lx, .y = ly }; scene_node_get_size(node, &node_box.width, &node_box.height); @@ -246,6 +251,9 @@ static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y, if (scene_rect->color[3] != 1) { return; } + } else if (node->type == WLR_SCENE_NODE_SHADOW) { + // TODO: test & handle case of blur sigma = 0 and color[3] = 1? + return; } else if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); @@ -258,10 +266,7 @@ static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y, } if (scene_buffer->corner_radius > 0) { - return; - } - - if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) { + // TODO: this is incorrect return; } @@ -474,24 +479,6 @@ static bool scene_node_update_iterator(struct wlr_scene_node *node, pixman_region32_fini(&opaque); } - // Expand the nodes visible region by the shadow size - if (node->type == WLR_SCENE_NODE_BUFFER) { - struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); - struct shadow_data *shadow_data = &buffer->shadow_data; - if (scene_buffer_has_shadow(shadow_data)) { - // Expand towards the damage while also compensating for the x and y - // offsets - pixman_region32_t shadow; - pixman_region32_init(&shadow); - pixman_region32_copy(&shadow, &node->visible); - wlr_region_expand(&shadow, &shadow, shadow_data->blur_sigma); - pixman_region32_translate(&shadow, shadow_data->offset_x, shadow_data->offset_y); - pixman_region32_subtract(&shadow, &shadow, &node->visible); - pixman_region32_union(&node->visible, &node->visible, &shadow); - pixman_region32_fini(&shadow); - } - } - update_node_update_outputs(node, data->outputs, NULL, NULL); return false; @@ -634,6 +621,64 @@ void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[sta scene_node_update(&rect->node, NULL); } +struct wlr_scene_shadow *wlr_scene_shadow_create(struct wlr_scene_tree *parent, + int width, int height, int corner_radius, float blur_sigma, + const float color [static 4]) { + struct wlr_scene_shadow *scene_shadow = calloc(1, sizeof(*scene_shadow)); + if (scene_shadow == NULL) { + return NULL; + } + assert(parent); + scene_node_init(&scene_shadow->node, WLR_SCENE_NODE_SHADOW, parent); + + scene_shadow->width = width; + scene_shadow->height = height; + scene_shadow->corner_radius = corner_radius; + scene_shadow->blur_sigma = blur_sigma; + memcpy(scene_shadow->color, color, sizeof(scene_shadow->color)); + + scene_node_update(&scene_shadow->node, NULL); + + return scene_shadow; +} + +void wlr_scene_shadow_set_size(struct wlr_scene_shadow *shadow, int width, int height) { + if (shadow->width == width && shadow->height == height) { + return; + } + + shadow->width = width; + shadow->height = height; + scene_node_update(&shadow->node, NULL); +} + +void wlr_scene_shadow_set_corner_radius(struct wlr_scene_shadow *shadow, int corner_radius) { + if (shadow->corner_radius == corner_radius) { + return; + } + + shadow->corner_radius = corner_radius; + scene_node_update(&shadow->node, NULL); +} + +void wlr_scene_shadow_set_blur_sigma(struct wlr_scene_shadow *shadow, float blur_sigma) { + if (shadow->blur_sigma == blur_sigma) { + return; + } + + shadow->blur_sigma = blur_sigma; + scene_node_update(&shadow->node, NULL); +} + +void wlr_scene_shadow_set_color(struct wlr_scene_shadow *shadow, const float color[static 4]) { + if (memcmp(shadow->color, color, sizeof(shadow->color)) == 0) { + return; + } + + memcpy(shadow->color, color, sizeof(shadow->color)); + scene_node_update(&shadow->node, NULL); +} + struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, struct wlr_buffer *buffer) { struct wlr_scene_buffer *scene_buffer = calloc(1, sizeof(*scene_buffer)); @@ -655,7 +700,6 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, pixman_region32_init(&scene_buffer->opaque_region); scene_buffer->opacity = 1; scene_buffer->corner_radius = 0; - scene_buffer->shadow_data = shadow_data_get_default(); scene_node_update(&scene_buffer->node, NULL); @@ -886,25 +930,6 @@ void wlr_scene_buffer_set_corner_radius(struct wlr_scene_buffer *scene_buffer, scene_node_update(&scene_buffer->node, NULL); } -void wlr_scene_buffer_set_shadow_data(struct wlr_scene_buffer *scene_buffer, - struct shadow_data shadow_data) { - struct shadow_data *buff_data = &scene_buffer->shadow_data; - if (buff_data->enabled == shadow_data.enabled && - buff_data->blur_sigma == shadow_data.blur_sigma && - buff_data->offset_x == shadow_data.offset_x && - buff_data->offset_y == shadow_data.offset_y && - buff_data->color.r && shadow_data.color.r && - buff_data->color.g && shadow_data.color.g && - buff_data->color.b && shadow_data.color.b && - buff_data->color.a && shadow_data.color.a) { - return; - } - - memcpy(&scene_buffer->shadow_data, &shadow_data, - sizeof(struct shadow_data)); - scene_node_update(&scene_buffer->node, NULL); -} - static struct wlr_texture *scene_buffer_get_texture( struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) { struct wlr_client_buffer *client_buffer = @@ -935,6 +960,12 @@ static void scene_node_get_size(struct wlr_scene_node *node, *width = scene_rect->width; *height = scene_rect->height; break; + case WLR_SCENE_NODE_SHADOW:; + // TODO: compensate for blur_sigma? may not be needed + struct wlr_scene_shadow *scene_shadow = wlr_scene_shadow_from_node(node); + *width = scene_shadow->width; + *height = scene_shadow->height; + break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); if (scene_buffer->dst_width > 0 && scene_buffer->dst_height > 0) { @@ -953,6 +984,25 @@ static void scene_node_get_size(struct wlr_scene_node *node, } } +static void scene_node_get_corner_radius(struct wlr_scene_node *node, int *corner_radius) { + *corner_radius = 0; + + switch (node->type) { + case WLR_SCENE_NODE_TREE: + return; + case WLR_SCENE_NODE_RECT:; + return; + case WLR_SCENE_NODE_SHADOW:; + struct wlr_scene_shadow *scene_shadow = wlr_scene_shadow_from_node(node); + *corner_radius = scene_shadow->corner_radius; + break; + case WLR_SCENE_NODE_BUFFER:; + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); + *corner_radius = scene_buffer->corner_radius; + break; + } +} + static int scale_length(int length, int offset, float scale) { return round((offset + length) * scale) - round(offset * scale); } @@ -1133,6 +1183,9 @@ static bool scene_node_at_iterator(struct wlr_scene_node *node, !scene_buffer->point_accepts_input(scene_buffer, &rx, &ry)) { return false; } + } else if (node->type == WLR_SCENE_NODE_SHADOW) { + // Disable interaction + return false; } at_data->rx = rx; @@ -1168,6 +1221,67 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, return NULL; } +static void get_tree_geometry(struct wlr_scene_node *node, + pixman_region32_t *region, int *max_corner_radius) { + if (!node->enabled) { + return; + } + + if (node->type == WLR_SCENE_NODE_BUFFER || node->type == WLR_SCENE_NODE_RECT) { + struct wlr_box child_box = {0}; + int radius = 0; + wlr_scene_node_coords(node, &child_box.x, &child_box.y); + scene_node_get_size(node, &child_box.width, &child_box.height); + scene_node_get_corner_radius(node, &radius); + + pixman_region32_union_rect(region, region, + child_box.x, child_box.y, child_box.width, child_box.height); + if (radius > *max_corner_radius) { + *max_corner_radius = radius; + } + } else if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node); + struct wlr_scene_node *node; + wl_list_for_each(node, &tree->children, link) { + // Could possibly be a tree, so look through it as well + get_tree_geometry(node, region, max_corner_radius); + } + } +} + +static void scene_get_next_sibling_geometry(struct wlr_scene_node *node, + struct wlr_box *box, int *corner_radius) { + assert(box && corner_radius); + + *box = (struct wlr_box) {0}; + *corner_radius = 0; + + // Don't check if it's the only child in the tree + if (node->link.next == node->link.prev) { + return; + } + + struct wlr_scene_node *sibling_node = + wl_container_of(node->link.next, sibling_node, link); + + pixman_region32_t region; + pixman_region32_init(®ion); + + get_tree_geometry(sibling_node, ®ion, corner_radius); + + if (pixman_region32_not_empty(®ion)) { + struct pixman_box32 *region_box = pixman_region32_extents(®ion); + *box = (struct wlr_box){ + .x = region_box->x1, + .y = region_box->y1, + .width = region_box->x2 - region_box->x1, + .height = region_box->y2 - region_box->y1, + }; + } + + pixman_region32_fini(®ion); +} + struct render_list_entry { struct wlr_scene_node *node; bool sent_dmabuf_feedback; @@ -1198,9 +1312,6 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren scene_node_get_size(node, &dst_box.width, &dst_box.height); scale_box(&dst_box, data->scale); - // Shadow box - struct wlr_box shadow_box = dst_box; - pixman_region32_t opaque; pixman_region32_init(&opaque); scene_node_opaque_region(node, x, y, &opaque); @@ -1231,6 +1342,36 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren }; fx_render_pass_add_rect(data->render_pass, &rect_options); break; + case WLR_SCENE_NODE_SHADOW:; + struct wlr_scene_shadow *scene_shadow = wlr_scene_shadow_from_node(node); + + // Look through the first direct sibling node and get the size of the + // node. If the sibling is a tree, get the total size of the whole tree. + // Cannot grab the first buffer in the tree due to it potentially being + // a CSD surface and not the actual toplevel surface. + struct wlr_box window_box; + int window_corner_radius; + scene_get_next_sibling_geometry(node, &window_box, &window_corner_radius); + + transform_output_box(&window_box, data); + + struct fx_render_box_shadow_options shadow_options = { + .box = dst_box, + // TODO: Use dst_box if larger? + .window_box = window_box, + .window_corner_radius = window_corner_radius, + .blur_sigma = scene_shadow->blur_sigma, + .corner_radius = scene_shadow->corner_radius, + .color = { + .r = scene_shadow->color[0], + .g = scene_shadow->color[1], + .b = scene_shadow->color[2], + .a = scene_shadow->color[3], + }, + .clip = &render_region, + }; + fx_render_pass_add_box_shadow(data->render_pass, &shadow_options); + break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); assert(scene_buffer->buffer); @@ -1245,27 +1386,6 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren wlr_output_transform_invert(scene_buffer->transform); transform = wlr_output_transform_compose(transform, data->transform); - // Shadow - if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) { - struct shadow_data shadow_data = scene_buffer->shadow_data; - shadow_box.x -= shadow_data.blur_sigma - shadow_data.offset_x; - shadow_box.y -= shadow_data.blur_sigma - shadow_data.offset_y; - shadow_box.width += shadow_data.blur_sigma * 2; - shadow_box.height += shadow_data.blur_sigma * 2; - transform_output_box(&shadow_box, data); - - shadow_data.color.a *= scene_buffer->opacity; - - struct fx_render_box_shadow_options shadow_options = { - .shadow_box = shadow_box, - .clip_box = dst_box, - .clip = &render_region, - .shadow_data = &shadow_data, - .corner_radius = scene_buffer->corner_radius * data->scale, - }; - fx_render_pass_add_box_shadow(data->render_pass, &shadow_options); - } - struct fx_render_texture_options tex_options = { .base = (struct wlr_render_texture_options){ .texture = texture, @@ -1512,6 +1632,10 @@ static bool scene_node_invisible(struct wlr_scene_node *node) { struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node); return rect->color[3] == 0.f; + } else if (node->type == WLR_SCENE_NODE_SHADOW) { + struct wlr_scene_shadow *shadow = wlr_scene_shadow_from_node(node); + + return shadow->color[3] == 0.f; } else if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); |