UI: Improve menu dropshadow #111794
|
@ -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]);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
/**
|
||||
* <pre>
|
||||
* v1-_
|
||||
* | -_v2
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* v7_______v3____v4
|
||||
* \ | /
|
||||
* \ | _v5
|
||||
* v8______v6_-
|
||||
* </pre>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -91,8 +91,6 @@
|
|||
|
||||
#include "GEO_fillet_curves.hh"
|
||||
|
||||
#include "../interface/interface_intern.hh" /* TODO: Remove */
|
||||
|
||||
#include "node_intern.hh" /* own include */
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue