diff --git a/source/blender/editors/include/UI_interface_c.hh b/source/blender/editors/include/UI_interface_c.hh index d2de4d3523f..1d28e64454f 100644 --- a/source/blender/editors/include/UI_interface_c.hh +++ b/source/blender/editors/include/UI_interface_c.hh @@ -493,7 +493,8 @@ void UI_draw_roundbox_4fv_ex(const rctf *rect, int UI_draw_roundbox_corner_get(); #endif -void UI_draw_box_shadow(const rctf *rect, unsigned char alpha); +void ui_draw_dropshadow(const rctf *rct, float radius, float width, float aspect, float alpha); + void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4]); /** diff --git a/source/blender/editors/interface/interface_draw.cc b/source/blender/editors/interface/interface_draw.cc index 2ddfdd74a7b..16cad5ef7d9 100644 --- a/source/blender/editors/interface/interface_draw.cc +++ b/source/blender/editors/interface/interface_draw.cc @@ -2178,108 +2178,20 @@ void ui_draw_but_TRACKPREVIEW(ARegion * /*region*/, /* ****************************************************** */ -/* TODO(merwin): high quality UI drop shadows using GLSL shader and single draw call - * would replace / modify the following 3 functions. */ - -static void ui_shadowbox(const rctf *rect, uint pos, uint color, float shadsize, uchar alpha) +void ui_draw_dropshadow( + const rctf *rct, const float radius, const float width, const float aspect, const float alpha) { - /** - *
-   *          v1-_
-   *          |   -_v2
-   *          |     |
-   *          |     |
-   *          |     |
-   * v7_______v3____v4
-   * \        |     /
-   *  \       |   _v5
-   *  v8______v6_-
-   * 
- */ - const float v1[2] = {rect->xmax, rect->ymax - 0.3f * shadsize}; - const float v2[2] = {rect->xmax + shadsize, rect->ymax - 0.75f * shadsize}; - const float v3[2] = {rect->xmax, rect->ymin}; - const float v4[2] = {rect->xmax + shadsize, rect->ymin}; + if (width == 0.0f) { + return; + } - const float v5[2] = {rect->xmax + 0.7f * shadsize, rect->ymin - 0.7f * shadsize}; - - const float v6[2] = {rect->xmax, rect->ymin - shadsize}; - const float v7[2] = {rect->xmin + 0.3f * shadsize, rect->ymin}; - const float v8[2] = {rect->xmin + 0.5f * shadsize, rect->ymin - shadsize}; - - /* right quad */ - immAttr4ub(color, 0, 0, 0, alpha); - immVertex2fv(pos, v3); - immVertex2fv(pos, v1); - immAttr4ub(color, 0, 0, 0, 0); - immVertex2fv(pos, v2); - - immVertex2fv(pos, v2); - immVertex2fv(pos, v4); - immAttr4ub(color, 0, 0, 0, alpha); - immVertex2fv(pos, v3); - - /* corner shape */ - // immAttr4ub(color, 0, 0, 0, alpha); /* Not needed, done above in previous tri. */ - immVertex2fv(pos, v3); - immAttr4ub(color, 0, 0, 0, 0); - immVertex2fv(pos, v4); - immVertex2fv(pos, v5); - - immVertex2fv(pos, v5); - immVertex2fv(pos, v6); - immAttr4ub(color, 0, 0, 0, alpha); - immVertex2fv(pos, v3); - - /* bottom quad */ - // immAttr4ub(color, 0, 0, 0, alpha); /* Not needed, done above in previous tri. */ - immVertex2fv(pos, v3); - immAttr4ub(color, 0, 0, 0, 0); - immVertex2fv(pos, v6); - immVertex2fv(pos, v8); - - immVertex2fv(pos, v8); - immAttr4ub(color, 0, 0, 0, alpha); - immVertex2fv(pos, v7); - immVertex2fv(pos, v3); -} - -void UI_draw_box_shadow(const rctf *rect, uchar alpha) -{ - GPU_blend(GPU_BLEND_ALPHA); - - GPUVertFormat *format = immVertexFormat(); - const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - uint color = GPU_vertformat_attr_add( - format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - - immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR); - - immBegin(GPU_PRIM_TRIS, 54); - - /* accumulated outline boxes to make shade not linear, is more pleasant */ - ui_shadowbox(rect, pos, color, 11.0, (20 * alpha) >> 8); - ui_shadowbox(rect, pos, color, 7.0, (40 * alpha) >> 8); - ui_shadowbox(rect, pos, color, 5.0, (80 * alpha) >> 8); - - immEnd(); - - immUnbindProgram(); - - GPU_blend(GPU_BLEND_NONE); -} - -void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int /*select*/) -{ /* This undoes the scale of the view for higher zoom factors to clamp the shadow size. */ const float clamped_aspect = smoothminf(aspect, 1.0f, 0.5f); + const float shadow_width = width * clamped_aspect; + const float shadow_offset = min_ff(shadow_width, BLI_rctf_size_y(rct) - 2.0f * radius); - const float shadow_softness = 0.6f * U.widget_unit * clamped_aspect; - const float shadow_offset = 0.5f * U.widget_unit * clamped_aspect; - const float shadow_alpha = 0.5f * alpha; - - const float max_radius = (BLI_rctf_size_y(rct) - shadow_offset) * 0.5f; - const float rad = min_ff(radius, max_radius); + const float inner_radius = max_ff(radius - U.pixelsize, 0.0); + const float shadow_radius = radius + shadow_width - U.pixelsize; GPU_blend(GPU_BLEND_ALPHA); @@ -2287,13 +2199,13 @@ void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha widget_params.recti.xmin = rct->xmin; widget_params.recti.ymin = rct->ymin; widget_params.recti.xmax = rct->xmax; - widget_params.recti.ymax = rct->ymax - shadow_offset; - widget_params.rect.xmin = rct->xmin - shadow_softness; - widget_params.rect.ymin = rct->ymin - shadow_softness; - widget_params.rect.xmax = rct->xmax + shadow_softness; - widget_params.rect.ymax = rct->ymax - shadow_offset + shadow_softness; - widget_params.radi = rad; - widget_params.rad = rad + shadow_softness; + widget_params.recti.ymax = rct->ymax; + widget_params.rect.xmin = rct->xmin - shadow_width; + widget_params.rect.ymin = rct->ymin - shadow_width; + widget_params.rect.xmax = rct->xmax + shadow_width; + widget_params.rect.ymax = rct->ymax + shadow_width - shadow_offset; + widget_params.radi = inner_radius; + widget_params.rad = shadow_radius; widget_params.round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f; widget_params.round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f; widget_params.round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f; @@ -2303,17 +2215,8 @@ void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha GPUBatch *batch = ui_batch_roundbox_shadow_get(); GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_SHADOW); GPU_batch_uniform_4fv_array(batch, "parameters", 4, (const float(*)[4]) & widget_params); - GPU_batch_uniform_1f(batch, "alpha", shadow_alpha); + GPU_batch_uniform_1f(batch, "alpha", alpha); GPU_batch_draw(batch); - /* outline emphasis */ - const float color[4] = {0.0f, 0.0f, 0.0f, 0.4f}; - rctf rect{}; - rect.xmin = rct->xmin - 0.5f; - rect.xmax = rct->xmax + 0.5f; - rect.ymin = rct->ymin - 0.5f; - rect.ymax = rct->ymax + 0.5f; - UI_draw_roundbox_4fv(&rect, false, radius + 0.5f, color); - GPU_blend(GPU_BLEND_NONE); } diff --git a/source/blender/editors/interface/interface_intern.hh b/source/blender/editors/interface/interface_intern.hh index abf1facc7ec..4d1e4d6fa8b 100644 --- a/source/blender/editors/interface/interface_intern.hh +++ b/source/blender/editors/interface/interface_intern.hh @@ -1028,10 +1028,6 @@ void ui_draw_aligned_panel(const uiStyle *style, bool region_search_filter_active); void ui_panel_tag_search_filter_match(Panel *panel); -/* interface_draw.cc */ - -void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int select); - /** * Draws in resolution of 48x4 colors. */ diff --git a/source/blender/editors/interface/interface_widgets.cc b/source/blender/editors/interface/interface_widgets.cc index 9fdc06f1a3e..31711ecf303 100644 --- a/source/blender/editors/interface/interface_widgets.cc +++ b/source/blender/editors/interface/interface_widgets.cc @@ -599,86 +599,6 @@ static void widget_init(uiWidgetBase *wtb) /** \name Draw Round Box * \{ */ -/* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */ -/* return tot */ -static int round_box_shadow_edges( - float (*vert)[2], const rcti *rect, float rad, int roundboxalign, float step) -{ - float vec[WIDGET_CURVE_RESOLU][2]; - int tot = 0; - - rad += step; - - if (2.0f * rad > BLI_rcti_size_y(rect)) { - rad = 0.5f * BLI_rcti_size_y(rect); - } - - const float minx = rect->xmin - step; - const float miny = rect->ymin - step; - const float maxx = rect->xmax + step; - const float maxy = rect->ymax + step; - - /* Multiply. */ - for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) { - vec[a][0] = rad * cornervec[a][0]; - vec[a][1] = rad * cornervec[a][1]; - } - - /* start with left-top, anti clockwise */ - if (roundboxalign & UI_CNR_TOP_LEFT) { - for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) { - vert[tot][0] = minx + rad - vec[a][0]; - vert[tot][1] = maxy - vec[a][1]; - } - } - else { - for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) { - vert[tot][0] = minx; - vert[tot][1] = maxy; - } - } - - if (roundboxalign & UI_CNR_BOTTOM_LEFT) { - for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) { - vert[tot][0] = minx + vec[a][1]; - vert[tot][1] = miny + rad - vec[a][0]; - } - } - else { - for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) { - vert[tot][0] = minx; - vert[tot][1] = miny; - } - } - - if (roundboxalign & UI_CNR_BOTTOM_RIGHT) { - for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) { - vert[tot][0] = maxx - rad + vec[a][0]; - vert[tot][1] = miny + vec[a][1]; - } - } - else { - for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) { - vert[tot][0] = maxx; - vert[tot][1] = miny; - } - } - - if (roundboxalign & UI_CNR_TOP_RIGHT) { - for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) { - vert[tot][0] = maxx - vec[a][1]; - vert[tot][1] = maxy - rad + vec[a][0]; - } - } - else { - for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) { - vert[tot][0] = maxx; - vert[tot][1] = maxy; - } - } - return tot; -} - /* this call has 1 extra arg to allow mask outline */ static void round_box__edges( uiWidgetBase *wt, int roundboxalign, const rcti *rect, float rad, float radi) @@ -2828,54 +2748,18 @@ static void widget_state_menu_item(uiWidgetType *wt, /* outside of rect, rad to left/bottom/right */ static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin) { - bTheme *btheme = UI_GetTheme(); - uiWidgetBase wtb; - rcti rect1 = *rect; - float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; - const float radout = UI_ThemeMenuShadowWidth(); + const float outline = U.pixelsize; - /* disabled shadow */ - if (radout == 0.0f) { - return; - } + rctf shadow_rect; + BLI_rctf_rcti_copy(&shadow_rect, rect); + BLI_rctf_pad(&shadow_rect, -outline, -outline); - /* prevent tooltips to not show round shadow */ - if (radout > 0.2f * BLI_rcti_size_y(&rect1)) { - rect1.ymax -= 0.2f * BLI_rcti_size_y(&rect1); - } - else { - rect1.ymax -= radout; - } + UI_draw_roundbox_corner_set(roundboxalign); - /* inner part */ - const int totvert = round_box_shadow_edges(wtb.inner_v, - &rect1, - radin, - roundboxalign & - (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT), - 0.0f); + const float shadow_alpha = UI_GetTheme()->tui.menu_shadow_fac; + const float shadow_width = UI_ThemeMenuShadowWidth(); - /* we draw a number of increasing size alpha quad strips */ - const float alphastep = 3.0f * btheme->tui.menu_shadow_fac / radout; - - const uint pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - for (int step = 1; step <= int(radout); step++) { - const float expfac = sqrtf(step / radout); - - round_box_shadow_edges(wtb.outer_v, &rect1, radin, UI_CNR_ALL, float(step)); - - immUniformColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac)); - - widget_verts_to_triangle_strip(&wtb, totvert, triangle_strip); - - widget_draw_vertex_buffer(pos, 0, GPU_PRIM_TRI_STRIP, triangle_strip, nullptr, totvert * 2); - } - - immUnbindProgram(); + ui_draw_dropshadow(&shadow_rect, radin, shadow_width, 1.0f, shadow_alpha); } static void widget_menu_back( @@ -5534,9 +5418,7 @@ static void ui_draw_widget_back_color(uiWidgetTypeEnum type, uiWidgetType *wt = widget_type(type); if (use_shadow) { - GPU_blend(GPU_BLEND_ALPHA); widget_softshadow(rect, UI_CNR_ALL, 0.25f * U.widget_unit); - GPU_blend(GPU_BLEND_NONE); } rcti rect_copy = *rect; diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index aa729e8200b..3167e9af8b6 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -91,8 +91,6 @@ #include "GEO_fillet_curves.hh" -#include "../interface/interface_intern.hh" /* TODO: Remove */ - #include "node_intern.hh" /* own include */ #include @@ -1857,7 +1855,20 @@ static void node_draw_shadow(const SpaceNode &snode, { const rctf &rct = node.runtime->totr; UI_draw_roundbox_corner_set(UI_CNR_ALL); - ui_draw_dropshadow(&rct, radius, snode.runtime->aspect, alpha, node.flag & SELECT); + + const float shadow_width = 0.6f * U.widget_unit; + const float shadow_alpha = 0.5f * alpha; + + ui_draw_dropshadow(&rct, radius, shadow_width, snode.runtime->aspect, shadow_alpha); + + /* Outline emphasis. Slight darkening _inside_ the outline. */ + const float color[4] = {0.0f, 0.0f, 0.0f, 0.4f}; + rctf rect{}; + rect.xmin = rct.xmin - 0.5f; + rect.xmax = rct.xmax + 0.5f; + rect.ymin = rct.ymin - 0.5f; + rect.ymax = rct.ymax + 0.5f; + UI_draw_roundbox_4fv(&rect, false, radius + 0.5f, color); } static void node_draw_sockets(const View2D &v2d, diff --git a/source/blender/editors/space_text/text_draw.cc b/source/blender/editors/space_text/text_draw.cc index 3a417df8024..aff1cc814e6 100644 --- a/source/blender/editors/space_text/text_draw.cc +++ b/source/blender/editors/space_text/text_draw.cc @@ -1056,7 +1056,7 @@ static void draw_suggestion_list(const SpaceText *st, const TextDrawContext *tdc rect.xmax = x + boxw; rect.ymin = y - boxh; rect.ymax = y; - UI_draw_box_shadow(&rect, 220); + ui_draw_dropshadow(&rect, 0.0f, 8.0f, 1.0f, 0.5f); } uint pos = GPU_vertformat_attr_add( diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl index 54b3657c3b2..bdaf9234a4f 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl @@ -6,5 +6,8 @@ void main() { fragColor = vec4(0.0); /* Manual curve fit of the falloff curve of previous drawing method. */ - fragColor.a = alpha * (shadowFalloff * shadowFalloff * 0.722 + shadowFalloff * 0.277); + float shadow_alpha = alpha * (shadowFalloff * shadowFalloff * 0.722 + shadowFalloff * 0.277); + float inner_alpha = smoothstep(0.0, 0.05, innerMask); + + fragColor.a = inner_alpha * shadow_alpha; } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl index e25bcc5a5f1..a6de1a0de02 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl @@ -67,17 +67,41 @@ void main() vec2(0.02, -0.805), vec2(0.0, -1.0)); + const vec2 center_offset[4] = vec2[4]( + vec2(1.0, 1.0), vec2(-1.0, 1.0), vec2(-1.0, -1.0), vec2(1.0, -1.0)); + uint cflag = vflag & CNR_FLAG_RANGE; uint vofs = (vflag >> CORNER_VEC_OFS) & CORNER_VEC_RANGE; - vec2 v = cornervec[cflag * 9u + vofs]; - bool is_inner = (vflag & INNER_FLAG) != 0u; - shadowFalloff = (is_inner) ? 1.0 : 0.0; + float shadow_width = rads - radsi; + float shadow_width_top = rect.w - recti.w; - /* Scale by corner radius */ - v *= roundCorners[cflag] * ((is_inner) ? radsi : rads); + float rad_inner = radsi * roundCorners[cflag]; + float rad_outer = rad_inner + shadow_width; + float radius = (is_inner) ? rad_inner : rad_outer; + + float shadow_offset = (is_inner && (cflag > BOTTOM_RIGHT)) ? (shadow_width - shadow_width_top) : + 0.0; + + vec2 c = center_offset[cflag]; + vec2 center_outer = rad_outer * c; + vec2 center = radius * c; + + /* First expand all vertices to the outer shadow border. */ + vec2 v = rad_outer * cornervec[cflag * 9u + vofs]; + + /* Now shrink the inner vertices onto the inner rectangle. + * At the top corners we keep the vertical offset to distribute a few of the vertices along the + * straight part of the rectangle. This allows us to get a better falloff at the top. */ + if (is_inner && (cflag > BOTTOM_RIGHT) && (v.y < (shadow_offset - rad_outer))) { + v.y += shadow_width_top; + v.x = 0.0; + } + else { + v = radius * normalize(v - (center_outer + vec2(0.0, shadow_offset))) + center; + } /* Position to corner */ vec4 rct = (is_inner) ? recti : rect; @@ -94,5 +118,9 @@ void main() v += rct.xw; } + float inner_shadow_strength = min((rect.w - v.y) / rad_outer + 0.1, 1.0); + shadowFalloff = (is_inner) ? inner_shadow_strength : 0.0; + innerMask = (is_inner) ? 0.0 : 1.0; + gl_Position = ModelViewProjectionMatrix * vec4(v, 0.0, 1.0); } diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_widget_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_widget_info.hh index 467d8cb0c80..b7cd0419807 100644 --- a/source/blender/gpu/shaders/infos/gpu_shader_2D_widget_info.hh +++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_widget_info.hh @@ -49,7 +49,9 @@ GPU_SHADER_CREATE_INFO(gpu_shader_2D_widget_base_inst) .push_constant(Type::VEC4, "parameters", (MAX_PARAM * MAX_INSTANCE)) .additional_info("gpu_shader_2D_widget_shared"); -GPU_SHADER_INTERFACE_INFO(gpu_widget_shadow_iface, "").smooth(Type::FLOAT, "shadowFalloff"); +GPU_SHADER_INTERFACE_INFO(gpu_widget_shadow_iface, "") + .smooth(Type::FLOAT, "shadowFalloff") + .smooth(Type::FLOAT, "innerMask"); GPU_SHADER_CREATE_INFO(gpu_shader_2D_widget_shadow) .do_static_compilation(true)