diff --git a/include/render/fx_renderer/shaders.h b/include/render/fx_renderer/shaders.h index 539a802b..fe3a19a9 100644 --- a/include/render/fx_renderer/shaders.h +++ b/include/render/fx_renderer/shaders.h @@ -46,10 +46,10 @@ struct quad_grad_shader { GLint degree; GLint grad_box; GLint pos_attrib; - GLint linear; + GLint is_linear; GLint origin; GLint count; - GLint blend; + GLint should_blend; }; bool link_quad_grad_program(struct quad_grad_shader *shader, GLint client_version, int max_len); @@ -89,10 +89,10 @@ struct quad_grad_round_shader { GLint grad_size; GLint degree; GLint grad_box; - GLint linear; + GLint is_linear; GLint origin; GLint count; - GLint blend; + GLint should_blend; GLint radius_top_left; GLint radius_top_right; diff --git a/include/scenefx/render/pass.h b/include/scenefx/render/pass.h index ce1caf9c..0dc51b14 100644 --- a/include/scenefx/render/pass.h +++ b/include/scenefx/render/pass.h @@ -9,6 +9,7 @@ #include "render/egl.h" #include "scenefx/types/fx/clipped_region.h" #include "scenefx/types/fx/corner_location.h" +#include "scenefx/types/fx/gradient.h" struct fx_gles_render_pass { struct wlr_render_pass base; @@ -38,20 +39,6 @@ struct fx_gles_render_pass *fx_renderer_begin_buffer_pass(struct wlr_renderer *w struct wlr_buffer *wlr_buffer, struct wlr_output *output, const struct fx_buffer_pass_options *options); -struct fx_gradient { - float degree; - /* The full area the gradient fit too, for borders use the window size */ - struct wlr_box range; - /* The center of the gradient, {0.5, 0.5} for normal*/ - float origin[2]; - /* 1 = Linear, 2 = Conic */ - int linear; - /* Whether or not to blend the colors */ - int blend; - int count; - float *colors; -}; - struct fx_render_texture_options { struct wlr_render_texture_options base; const struct wlr_box *clip_box; // Used to clip csd. Ignored if NULL @@ -66,8 +53,8 @@ struct fx_render_rect_options { }; struct fx_render_rect_grad_options { - struct wlr_render_rect_options base; - struct fx_gradient gradient; + struct fx_render_rect_options rect_options; + struct gradient gradient; }; struct fx_render_rounded_rect_options { @@ -78,10 +65,8 @@ struct fx_render_rounded_rect_options { }; struct fx_render_rounded_rect_grad_options { - struct wlr_render_rect_options base; - struct fx_gradient gradient; - int corner_radius; - enum corner_location corners; + struct fx_render_rounded_rect_options rounded_rect_options; + struct gradient gradient; }; struct fx_render_box_shadow_options { diff --git a/include/scenefx/types/fx/gradient.h b/include/scenefx/types/fx/gradient.h new file mode 100644 index 00000000..dd6bf072 --- /dev/null +++ b/include/scenefx/types/fx/gradient.h @@ -0,0 +1,14 @@ +#ifndef TYPES_FX_GRADIENT_H +#define TYPES_FX_GRADIENT_H + +struct gradient { + float degree; + struct wlr_box range; // the full area the gradient fit to, for borders use the window size + float origin[2]; // center of the gradient, { 0.5, 0.5 } for normal + bool is_linear; // else is conic + float should_blend; + int count; + float *colors; +}; + +#endif // TYPES_FX_GRADIENT_H diff --git a/include/scenefx/types/wlr_scene.h b/include/scenefx/types/wlr_scene.h index ca1e05a8..7556337e 100644 --- a/include/scenefx/types/wlr_scene.h +++ b/include/scenefx/types/wlr_scene.h @@ -31,6 +31,7 @@ #include "scenefx/types/fx/blur_data.h" #include "scenefx/types/fx/clipped_region.h" #include "scenefx/types/fx/corner_location.h" +#include "scenefx/types/fx/gradient.h" struct wlr_output; struct wlr_output_layout; @@ -91,6 +92,11 @@ enum wlr_scene_debug_damage_option { WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT }; +enum wlr_scene_rect_fill_type { + SOLID_COLOR, + GRADIENT, +}; + /** A sub-tree in the scene-graph. */ struct wlr_scene_tree { struct wlr_scene_node node; @@ -146,7 +152,6 @@ struct wlr_scene_surface { struct wlr_scene_rect { struct wlr_scene_node node; int width, height; - float color[4]; int corner_radius; enum corner_location corners; bool backdrop_blur; @@ -154,6 +159,12 @@ struct wlr_scene_rect { float backdrop_blur_strength; float backdrop_blur_alpha; + union { + float color[4]; + struct gradient gradient; + }; + enum wlr_scene_rect_fill_type fill_type; + bool accepts_input; struct clipped_region clipped_region; }; @@ -526,6 +537,11 @@ void wlr_scene_rect_set_clipped_region(struct wlr_scene_rect *rect, */ void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[static 4]); +/** + * Change the gradient of an existing rectangle node. + */ +void wlr_scene_rect_set_gradient(struct wlr_scene_rect *rect, const struct gradient gradient); + /** * Sets whether or not the buffer should render backdrop blur */ diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index f3ec78b7..41ed8de2 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -450,7 +450,7 @@ void fx_render_pass_add_rect(struct fx_gles_render_pass *pass, void fx_render_pass_add_rect_grad(struct fx_gles_render_pass *pass, const struct fx_render_rect_grad_options *fx_options) { - const struct wlr_render_rect_options *options = &fx_options->base; + const struct wlr_render_rect_options *options = &fx_options->rect_options.base; struct fx_renderer *renderer = pass->buffer->renderer; @@ -479,8 +479,8 @@ void fx_render_pass_add_rect_grad(struct fx_gles_render_pass *pass, glUniform1i(renderer->shaders.quad_grad.count, fx_options->gradient.count); glUniform2f(renderer->shaders.quad_grad.size, fx_options->gradient.range.width, fx_options->gradient.range.height); glUniform1f(renderer->shaders.quad_grad.degree, fx_options->gradient.degree); - glUniform1f(renderer->shaders.quad_grad.linear, fx_options->gradient.linear); - glUniform1f(renderer->shaders.quad_grad.blend, fx_options->gradient.blend); + glUniform1f(renderer->shaders.quad_grad.is_linear, fx_options->gradient.is_linear); + glUniform1f(renderer->shaders.quad_grad.should_blend, fx_options->gradient.should_blend); glUniform2f(renderer->shaders.quad_grad.grad_box, fx_options->gradient.range.x, fx_options->gradient.range.y); glUniform2f(renderer->shaders.quad_grad.origin, fx_options->gradient.origin[0], fx_options->gradient.origin[1]); @@ -566,7 +566,7 @@ void fx_render_pass_add_rounded_rect(struct fx_gles_render_pass *pass, void fx_render_pass_add_rounded_rect_grad(struct fx_gles_render_pass *pass, const struct fx_render_rounded_rect_grad_options *fx_options) { - const struct wlr_render_rect_options *options = &fx_options->base; + const struct wlr_render_rect_options *options = &fx_options->rounded_rect_options.base; struct fx_renderer *renderer = pass->buffer->renderer; @@ -600,20 +600,20 @@ void fx_render_pass_add_rounded_rect_grad(struct fx_gles_render_pass *pass, glUniform1i(shader.count, fx_options->gradient.count); glUniform2f(shader.grad_size, fx_options->gradient.range.width, fx_options->gradient.range.height); glUniform1f(shader.degree, fx_options->gradient.degree); - glUniform1f(shader.linear, fx_options->gradient.linear); - glUniform1f(shader.blend, fx_options->gradient.blend); + glUniform1f(shader.is_linear, fx_options->gradient.is_linear); + glUniform1f(shader.should_blend, fx_options->gradient.should_blend); glUniform2f(shader.grad_box, fx_options->gradient.range.x, fx_options->gradient.range.y); glUniform2f(shader.origin, fx_options->gradient.origin[0], fx_options->gradient.origin[1]); - enum corner_location corners = fx_options->corners; + enum corner_location corners = fx_options->rounded_rect_options.corners; glUniform1f(shader.radius_top_left, (CORNER_LOCATION_TOP_LEFT & corners) == CORNER_LOCATION_TOP_LEFT ? - fx_options->corner_radius : 0); + fx_options->rounded_rect_options.corner_radius : 0); glUniform1f(shader.radius_top_right, (CORNER_LOCATION_TOP_RIGHT & corners) == CORNER_LOCATION_TOP_RIGHT ? - fx_options->corner_radius : 0); + fx_options->rounded_rect_options.corner_radius : 0); glUniform1f(shader.radius_bottom_left, (CORNER_LOCATION_BOTTOM_LEFT & corners) == CORNER_LOCATION_BOTTOM_LEFT ? - fx_options->corner_radius : 0); + fx_options->rounded_rect_options.corner_radius : 0); glUniform1f(shader.radius_bottom_right, (CORNER_LOCATION_BOTTOM_RIGHT & corners) == CORNER_LOCATION_BOTTOM_RIGHT ? - fx_options->corner_radius : 0); + fx_options->rounded_rect_options.corner_radius : 0); render(&box, options->clip, shader.pos_attrib); diff --git a/render/fx_renderer/gles2/shaders/gradient.frag b/render/fx_renderer/gles2/shaders/gradient.frag index 407e2730..8e506fd6 100644 --- a/render/fx_renderer/gles2/shaders/gradient.frag +++ b/render/fx_renderer/gles2/shaders/gradient.frag @@ -1,4 +1,5 @@ -vec4 gradient(vec4 colors[LEN], int count, vec2 size, vec2 grad_box, vec2 origin, float degree, bool linear, bool blend) { +vec4 gradient(vec4 colors[LEN], int count, vec2 size, vec2 grad_box, + vec2 origin, float degree, bool is_linear, bool should_blend) { float step; vec2 normal = (gl_FragCoord.xy - grad_box)/size; @@ -6,36 +7,35 @@ vec4 gradient(vec4 colors[LEN], int count, vec2 size, vec2 grad_box, vec2 origin float rad = radians(degree); - if (linear) { - uv *= vec2(1.0)/vec2(abs(cos(rad)) + abs(sin(rad))); - + if (is_linear) { + uv *= vec2(1.0) / vec2(abs(cos(rad)) + abs(sin(rad))); vec2 rotated = vec2(uv.x * cos(rad) - uv.y * sin(rad) + origin.x, - uv.x * sin(rad) + uv.y * cos(rad) + origin.y); - + uv.x * sin(rad) + uv.y * cos(rad) + origin.y); step = rotated.x; } else { vec2 uv = normal - origin; uv = vec2(uv.x * cos(rad) - uv.y * sin(rad), uv.x * sin(rad) + uv.y * cos(rad)); - uv = vec2(-atan(uv.y, uv.x)/3.14159265 * 0.5 + 0.5, 0.0); + uv = vec2(-atan(uv.y, uv.x) / 3.14159265 * 0.5 + 0.5, 0.0); step = uv.x; } - if (!blend) { - float smooth_fac = 1.0/float(count); - int ind = int(step/smooth_fac); + if (!should_blend) { + float smooth_fac = 1.0 / float(count); + int ind = int(step / smooth_fac); return colors[ind]; } - float smooth_fac = 1.0/float(count - 1); - int ind = int(step/smooth_fac); - float at = float(ind)*smooth_fac; + float smooth_fac = 1.0 / float(count - 1); + int ind = int(step / smooth_fac); + float at = float(ind) * smooth_fac; vec4 color = colors[ind]; - if(ind > 0) color = mix(colors[ind - 1], color, smoothstep(at - smooth_fac, at, step)); - if(ind <= count - 1) color = mix(color, colors[ind + 1], smoothstep(at, at + smooth_fac, step)); + if (ind > 0) color = mix(colors[ind - 1], color, smoothstep(at - smooth_fac, at, step)); + if (ind <= count - 1) color = mix(color, colors[ind + 1], smoothstep(at, at + smooth_fac, step)); return color; } + diff --git a/render/fx_renderer/gles2/shaders/quad_grad.frag b/render/fx_renderer/gles2/shaders/quad_grad.frag index fed138cd..0442694d 100644 --- a/render/fx_renderer/gles2/shaders/quad_grad.frag +++ b/render/fx_renderer/gles2/shaders/quad_grad.frag @@ -14,12 +14,14 @@ uniform vec2 size; uniform float degree; uniform vec2 grad_box; uniform vec2 origin; -uniform bool linear; -uniform bool blend; +uniform bool is_linear; +uniform bool should_blend; uniform int count; -vec4 gradient(vec4 colors[LEN], int count, vec2 size, vec2 grad_box, vec2 origin, float degree, bool linear, bool blend); +vec4 gradient(vec4 colors[LEN], int count, vec2 size, vec2 grad_box, + vec2 origin, float degree, bool is_linear, bool should_blend); void main(){ - gl_FragColor = gradient(colors, count, size, grad_box, origin, degree, linear, blend); + gl_FragColor = gradient(colors, count, size, grad_box, + origin, degree, is_linear, should_blend); } diff --git a/render/fx_renderer/gles2/shaders/quad_grad_round.frag b/render/fx_renderer/gles2/shaders/quad_grad_round.frag index bbf74006..faed5716 100644 --- a/render/fx_renderer/gles2/shaders/quad_grad_round.frag +++ b/render/fx_renderer/gles2/shaders/quad_grad_round.frag @@ -22,15 +22,15 @@ uniform vec2 grad_size; uniform float degree; uniform vec2 grad_box; uniform vec2 origin; -uniform bool linear; -uniform bool blend; +uniform bool is_linear; +uniform bool should_blend; uniform int count; -vec4 gradient(vec4 colors[LEN], int count, vec2 size, vec2 grad_box, vec2 origin, float degree, bool linear, bool blend); +vec4 gradient(vec4 colors[LEN], int count, vec2 size, vec2 grad_box, + vec2 origin, float degree, bool is_linear, bool should_blend); float corner_alpha(vec2 size, vec2 position, float round_tl, float round_tr, float round_bl, float round_br); -// TODO: void main() { float quad_corner_alpha = corner_alpha( size - 1.0, @@ -42,5 +42,9 @@ void main() { ); float rect_alpha = v_color.a * quad_corner_alpha; - gl_FragColor = mix(vec4(0), gradient(colors, count, size, grad_box, origin, degree, linear, blend), rect_alpha); + gl_FragColor = mix( + vec4(0.0), + gradient(colors, count, size, grad_box, origin, degree, is_linear, should_blend), + rect_alpha + ); } diff --git a/render/fx_renderer/gles3/shaders/gradient.frag b/render/fx_renderer/gles3/shaders/gradient.frag index f5522ac7..b4f1b32c 100644 --- a/render/fx_renderer/gles3/shaders/gradient.frag +++ b/render/fx_renderer/gles3/shaders/gradient.frag @@ -1,41 +1,40 @@ -vec4 gradient(vec4 colors[LEN], int count, vec2 size, vec2 grad_box, vec2 origin, float degree, bool linear, bool blend) { +vec4 gradient(vec4 colors[LEN], int count, vec2 size, vec2 grad_box, + vec2 origin, float degree, bool is_linear, bool should_blend) { float step; - vec2 normal = (gl_FragCoord.xy - grad_box)/size; + vec2 normal = (gl_FragCoord.xy - grad_box) / size; vec2 uv = normal - origin; float rad = radians(degree); - if (linear) { - uv *= vec2(1.0)/vec2(abs(cos(rad)) + abs(sin(rad))); - + if (is_linear) { + uv *= vec2(1.0) / vec2(abs(cos(rad)) + abs(sin(rad))); vec2 rotated = vec2(uv.x * cos(rad) - uv.y * sin(rad) + origin.x, - uv.x * sin(rad) + uv.y * cos(rad) + origin.y); - + uv.x * sin(rad) + uv.y * cos(rad) + origin.y); step = rotated.x; } else { vec2 uv = normal - origin; uv = vec2(uv.x * cos(rad) - uv.y * sin(rad), uv.x * sin(rad) + uv.y * cos(rad)); - uv = vec2(-atan(uv.y, uv.x)/3.14159265 * 0.5 + 0.5, 0.0); + uv = vec2(-atan(uv.y, uv.x) / 3.14159265 * 0.5 + 0.5, 0.0); step = uv.x; } - if (!blend) { + if (!should_blend) { float smooth_fac = 1.0/float(count); - int ind = int(step/smooth_fac); + int ind = int(step / smooth_fac); return colors[ind]; } - float smooth_fac = 1.0/float(count - 1); - int ind = int(step/smooth_fac); - float at = float(ind)*smooth_fac; + float smooth_fac = 1.0 / float(count - 1); + int ind = int(step / smooth_fac); + float at = float(ind) * smooth_fac; vec4 color = colors[ind]; - if(ind > 0) color = mix(colors[ind - 1], color, smoothstep(at - smooth_fac, at, step)); - if(ind <= count - 1) color = mix(color, colors[ind + 1], smoothstep(at, at + smooth_fac, step)); + if (ind > 0) color = mix(colors[ind - 1], color, smoothstep(at - smooth_fac, at, step)); + if (ind <= count - 1) color = mix(color, colors[ind + 1], smoothstep(at, at + smooth_fac, step)); return color; } diff --git a/render/fx_renderer/shaders.c b/render/fx_renderer/shaders.c index 2686a5b1..0ee3a047 100644 --- a/render/fx_renderer/shaders.c +++ b/render/fx_renderer/shaders.c @@ -173,10 +173,10 @@ bool link_quad_grad_program(struct quad_grad_shader *shader, GLint client_versio shader->colors = glGetUniformLocation(prog, "colors"); shader->degree = glGetUniformLocation(prog, "degree"); shader->grad_box = glGetUniformLocation(prog, "grad_box"); - shader->linear = glGetUniformLocation(prog, "linear"); + shader->is_linear = glGetUniformLocation(prog, "is_linear"); shader->origin = glGetUniformLocation(prog, "origin"); shader->count = glGetUniformLocation(prog, "count"); - shader->blend = glGetUniformLocation(prog, "blend"); + shader->should_blend = glGetUniformLocation(prog, "should_blend"); shader->max_len = max_len; @@ -254,10 +254,10 @@ bool link_quad_grad_round_program(struct quad_grad_round_shader *shader, GLint c shader->colors = glGetUniformLocation(prog, "colors"); shader->degree = glGetUniformLocation(prog, "degree"); shader->grad_box = glGetUniformLocation(prog, "grad_box"); - shader->linear = glGetUniformLocation(prog, "linear"); + shader->is_linear = glGetUniformLocation(prog, "is_linear"); shader->origin = glGetUniformLocation(prog, "origin"); shader->count = glGetUniformLocation(prog, "count"); - shader->blend = glGetUniformLocation(prog, "blend"); + shader->should_blend = glGetUniformLocation(prog, "should_blend"); shader->max_len = max_len; diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index c6e2a5de..77a53a8e 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -1133,26 +1133,37 @@ int main(int argc, char *argv[]) { /* Create all of the basic scene layers */ server.layers.bottom_layer = wlr_scene_tree_create(&server.scene->tree); + /* Add a bottom rect to demonstrate optimized blur */ float bottom_rect_color[4] = { 1, 1, 1, 1 }; - wlr_scene_rect_create(server.layers.bottom_layer, 200, 200, bottom_rect_color); + struct wlr_scene_rect *bottom_rect = wlr_scene_rect_create(server.layers.bottom_layer, + 200, 200, bottom_rect_color); + wlr_scene_rect_set_gradient( + bottom_rect, + (struct gradient) { + .degree = 0.0, + .range = (struct wlr_box) { + .x = 0, + .y = 0, + .width = 200, + .height = 200, + }, + .origin = { 0.5, 0.5 }, + .is_linear = true, + .should_blend = true, + .count = 1, + .colors = bottom_rect_color, + } + ); + /* Set the size later */ server.layers.blur_layer = wlr_scene_optimized_blur_create(&server.scene->tree, 0, 0); server.layers.toplevel_layer = wlr_scene_tree_create(&server.scene->tree); + /* Add a top rect that won't get blurred by optimized */ float top_rect_color[4] = { 1, 0, 0, 1 }; struct wlr_scene_rect *rect = wlr_scene_rect_create(server.layers.toplevel_layer, 200, 200, top_rect_color); - wlr_scene_rect_set_clipped_region(rect, (struct clipped_region) { - .corner_radius = 12, - .corners = CORNER_LOCATION_TOP, - .area = { - .x = 50, - .y = 50, - .width = 100, - .height = 100, - }, - }); wlr_scene_node_set_position(&rect->node, 200, 200); /* Set up xdg-shell version 3. The xdg-shell is a Wayland protocol which is diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 5973537c..b0380f4f 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -849,7 +849,7 @@ void wlr_scene_rect_set_size(struct wlr_scene_rect *rect, int width, int height) } void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[static 4]) { - if (memcmp(rect->color, color, sizeof(rect->color)) == 0) { + if (rect->fill_type == SOLID_COLOR && memcmp(rect->color, color, sizeof(rect->color)) == 0) { return; } @@ -857,6 +857,18 @@ void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[sta scene_node_update(&rect->node, NULL); } +void wlr_scene_rect_set_gradient(struct wlr_scene_rect *rect, const struct gradient gradient) { + // TODO: proper check + if (rect->fill_type == GRADIENT && false) { + return; + } + + rect->fill_type = GRADIENT; + rect->gradient = gradient; + + scene_node_update(&rect->node, NULL); +} + void wlr_scene_rect_set_backdrop_blur(struct wlr_scene_rect *rect, bool enabled) { if (rect->backdrop_blur == enabled) { @@ -1870,6 +1882,7 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren wlr_output_transform_compose(WL_OUTPUT_TRANSFORM_NORMAL, data->transform); struct wlr_scene *scene = data->output->scene; + // TODO: function for each case? switch (node->type) { case WLR_SCENE_NODE_TREE: assert(false); @@ -1928,15 +1941,18 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren transform_output_box(&rect_clipped_region_box, data); corner_location_transform(node_transform, &rect_clipped_corners); + struct wlr_render_color rect_color = { 0.0, 0.0, 0.0, 1.0 }; + if (scene_rect->fill_type == SOLID_COLOR) { + rect_color.r = scene_rect->color[0]; + rect_color.g = scene_rect->color[1]; + rect_color.b = scene_rect->color[2]; + rect_color.a = scene_rect->color[3]; + } + struct fx_render_rect_options rect_options = { .base = { .box = dst_box, - .color = { - .r = scene_rect->color[0], - .g = scene_rect->color[1], - .b = scene_rect->color[2], - .a = scene_rect->color[3], - }, + .color = rect_color, .clip = &render_region, }, .clipped_region = { @@ -1953,9 +1969,21 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren .corners = rect_corners, .clipped_region = rect_options.clipped_region, }; - fx_render_pass_add_rounded_rect(data->render_pass, &rounded_rect_options); + if (scene_rect->fill_type == SOLID_COLOR) { + fx_render_pass_add_rounded_rect(data->render_pass, &rounded_rect_options); + } else { + struct fx_render_rounded_rect_grad_options rounded_rect_grad_options = { + rounded_rect_options, scene_rect->gradient }; + fx_render_pass_add_rounded_rect_grad(data->render_pass, &rounded_rect_grad_options); + } } else { - fx_render_pass_add_rect(data->render_pass, &rect_options); + if (scene_rect->fill_type == SOLID_COLOR) { + fx_render_pass_add_rect(data->render_pass, &rect_options); + } else { + struct fx_render_rect_grad_options rect_grad_options = { + rect_options, scene_rect->gradient }; + fx_render_pass_add_rect_grad(data->render_pass, &rect_grad_options); + } } break; case WLR_SCENE_NODE_OPTIMIZED_BLUR:;