UI: Widget: Replace geometry by fragment shader drawing
This means all the antiailasing is done inside the fragment shader. We use a Signed Distance Field to draw the 2D rounded boxes. This ensure the best quality for AA. This reduce the averge Batch for widget to 16 verts instead of ~600 and reduce overshading a lot. Theme Emboss alpha and tria alpha needs to be changed after this refactor. The shadow drawing is left unchanged and still use geometry. Reviewed By: Severin Differential Revision: https://developer.blender.org/D7833
This commit is contained in:
parent
3cea42ce29
commit
15dda0115c
Notes:
blender-bot
2023-02-14 07:31:34 +01:00
Referenced by commit 3d4231babf
, UI: Fix opacity of the popover arrow outline
Referenced by issue #88785, graphical bug with sliders on 4k screen
Referenced by issue #79615, UI: icons and widget emboss look different from earlier versions
Referenced by issue #78331, NLA [Channels] colors black and broken
Referenced by issue #78307, Drawing artifacts in the Blender UI on macOS
Referenced by issue #78237, NLA colors black and broken
|
@ -118,51 +118,53 @@ void UI_draw_roundbox_aa(
|
|||
bool filled, float minx, float miny, float maxx, float maxy, float rad, const float color[4])
|
||||
{
|
||||
uiWidgetBaseParameters widget_params = {
|
||||
.recti.xmin = minx,
|
||||
.recti.ymin = miny,
|
||||
.recti.xmax = maxx,
|
||||
.recti.ymax = maxy,
|
||||
.recti.xmin = minx + U.pixelsize,
|
||||
.recti.ymin = miny + U.pixelsize,
|
||||
.recti.xmax = maxx - U.pixelsize,
|
||||
.recti.ymax = maxy - U.pixelsize,
|
||||
.rect.xmin = minx,
|
||||
.rect.ymin = miny,
|
||||
.rect.xmax = maxx,
|
||||
.rect.ymax = maxy,
|
||||
.radi = rad,
|
||||
.rad = rad,
|
||||
.round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
|
||||
.round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
|
||||
.round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
|
||||
.round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
|
||||
.color_inner1[0] = color[0],
|
||||
.color_inner2[0] = color[0],
|
||||
.color_inner1[1] = color[1],
|
||||
.color_inner2[1] = color[1],
|
||||
.color_inner1[2] = color[2],
|
||||
.color_inner2[2] = color[2],
|
||||
.color_inner1[3] = color[3],
|
||||
.color_inner2[3] = color[3],
|
||||
.color_inner1[0] = filled ? color[0] : 0.0f,
|
||||
.color_inner1[1] = filled ? color[1] : 0.0f,
|
||||
.color_inner1[2] = filled ? color[2] : 0.0f,
|
||||
.color_inner1[3] = filled ? color[3] : 0.0f,
|
||||
.color_inner2[0] = filled ? color[0] : 0.0f,
|
||||
.color_inner2[1] = filled ? color[1] : 0.0f,
|
||||
.color_inner2[2] = filled ? color[2] : 0.0f,
|
||||
.color_inner2[3] = filled ? color[3] : 0.0f,
|
||||
.color_outline[0] = color[0],
|
||||
.color_outline[1] = color[1],
|
||||
.color_outline[2] = color[2],
|
||||
.color_outline[3] = color[3],
|
||||
.alpha_discard = 1.0f,
|
||||
};
|
||||
|
||||
/* XXX this is to emulate previous behavior of semitransparent fills but that's was a side effect
|
||||
* of the previous AA method. Better fix the callers. */
|
||||
if (filled) {
|
||||
widget_params.color_inner1[3] *= 0.65f;
|
||||
widget_params.color_inner2[3] *= 0.65f;
|
||||
widget_params.color_outline[3] *= 0.65f;
|
||||
}
|
||||
|
||||
/* WATCH: This is assuming the ModelViewProjectionMatrix is area pixel space.
|
||||
* If it has been scaled, then it's no longer valid. */
|
||||
|
||||
GPUBatch *batch = ui_batch_roundbox_widget_get();
|
||||
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
|
||||
GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params);
|
||||
|
||||
GPU_blend(true);
|
||||
|
||||
if (filled) {
|
||||
/* plain antialiased filled box */
|
||||
widget_params.color_inner1[3] *= 0.125f;
|
||||
widget_params.color_inner2[3] *= 0.125f;
|
||||
|
||||
/* WATCH: This is assuming the ModelViewProjectionMatrix is area pixel space.
|
||||
* If it has been scaled, then it's no longer valid. */
|
||||
GPUBatch *batch = ui_batch_roundbox_get(filled, true);
|
||||
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
|
||||
GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params);
|
||||
GPU_batch_draw(batch);
|
||||
}
|
||||
else {
|
||||
/* plain antialiased unfilled box */
|
||||
GPU_line_smooth(true);
|
||||
|
||||
GPUBatch *batch = ui_batch_roundbox_get(filled, false);
|
||||
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
|
||||
GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params);
|
||||
GPU_batch_draw(batch);
|
||||
|
||||
GPU_line_smooth(false);
|
||||
}
|
||||
GPU_batch_draw(batch);
|
||||
|
||||
GPU_blend(false);
|
||||
}
|
||||
|
@ -251,32 +253,49 @@ void UI_draw_roundbox_4fv(
|
|||
immEnd();
|
||||
immUnbindProgram();
|
||||
#endif
|
||||
|
||||
uiWidgetBaseParameters widget_params = {
|
||||
.recti.xmin = minx,
|
||||
.recti.ymin = miny,
|
||||
.recti.xmax = maxx,
|
||||
.recti.ymax = maxy,
|
||||
.recti.xmin = minx + U.pixelsize,
|
||||
.recti.ymin = miny + U.pixelsize,
|
||||
.recti.xmax = maxx - U.pixelsize,
|
||||
.recti.ymax = maxy - U.pixelsize,
|
||||
.rect.xmin = minx,
|
||||
.rect.ymin = miny,
|
||||
.rect.xmax = maxx,
|
||||
.rect.ymax = maxy,
|
||||
.radi = rad,
|
||||
.rad = rad,
|
||||
.round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
|
||||
.round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
|
||||
.round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
|
||||
.round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
|
||||
.color_inner1[0] = col[0],
|
||||
.color_inner2[0] = col[0],
|
||||
.color_inner1[1] = col[1],
|
||||
.color_inner2[1] = col[1],
|
||||
.color_inner1[2] = col[2],
|
||||
.color_inner2[2] = col[2],
|
||||
.color_inner1[3] = col[3],
|
||||
.color_inner2[3] = col[3],
|
||||
.color_inner1[0] = filled ? col[0] : 0.0f,
|
||||
.color_inner1[1] = filled ? col[1] : 0.0f,
|
||||
.color_inner1[2] = filled ? col[2] : 0.0f,
|
||||
.color_inner1[3] = filled ? col[3] : 0.0f,
|
||||
.color_inner2[0] = filled ? col[0] : 0.0f,
|
||||
.color_inner2[1] = filled ? col[1] : 0.0f,
|
||||
.color_inner2[2] = filled ? col[2] : 0.0f,
|
||||
.color_inner2[3] = filled ? col[3] : 0.0f,
|
||||
.color_outline[0] = col[0],
|
||||
.color_outline[1] = col[1],
|
||||
.color_outline[2] = col[2],
|
||||
.color_outline[3] = col[3],
|
||||
.alpha_discard = 1.0f,
|
||||
};
|
||||
/* Exactly the same as UI_draw_roundbox_aa but does not do the legacy transparency. */
|
||||
|
||||
GPUBatch *batch = ui_batch_roundbox_get(filled, false);
|
||||
/* WATCH: This is assuming the ModelViewProjectionMatrix is area pixel space.
|
||||
* If it has been scaled, then it's no longer valid. */
|
||||
|
||||
GPUBatch *batch = ui_batch_roundbox_widget_get();
|
||||
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
|
||||
GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params);
|
||||
|
||||
GPU_blend(true);
|
||||
|
||||
GPU_batch_draw(batch);
|
||||
|
||||
GPU_blend(false);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -427,29 +446,38 @@ void UI_draw_roundbox_shade_x(bool filled,
|
|||
immEnd();
|
||||
immUnbindProgram();
|
||||
#endif
|
||||
|
||||
uiWidgetBaseParameters widget_params = {
|
||||
.recti.xmin = minx,
|
||||
.recti.ymin = miny,
|
||||
.recti.xmax = maxx,
|
||||
.recti.ymax = maxy,
|
||||
.recti.xmin = minx + U.pixelsize,
|
||||
.recti.ymin = miny + U.pixelsize,
|
||||
.recti.xmax = maxx - U.pixelsize,
|
||||
.recti.ymax = maxy - U.pixelsize,
|
||||
.rect.xmin = minx,
|
||||
.rect.ymin = miny,
|
||||
.rect.xmax = maxx,
|
||||
.rect.ymax = maxy,
|
||||
.radi = rad,
|
||||
.rad = rad,
|
||||
.round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
|
||||
.round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
|
||||
.round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
|
||||
.round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
|
||||
.color_inner1[0] = min_ff(1.0f, col[0] + shadetop),
|
||||
.color_inner2[0] = max_ff(0.0f, col[0] + shadedown),
|
||||
.color_inner1[1] = min_ff(1.0f, col[1] + shadetop),
|
||||
.color_inner2[1] = max_ff(0.0f, col[1] + shadedown),
|
||||
.color_inner1[2] = min_ff(1.0f, col[2] + shadetop),
|
||||
.color_inner2[2] = max_ff(0.0f, col[2] + shadedown),
|
||||
.color_inner1[3] = 1.0f,
|
||||
.color_inner2[3] = 1.0f,
|
||||
.color_inner1[0] = !filled ? 0.0f : min_ff(1.0f, col[0] + shadetop),
|
||||
.color_inner1[1] = !filled ? 0.0f : min_ff(1.0f, col[1] + shadetop),
|
||||
.color_inner1[2] = !filled ? 0.0f : min_ff(1.0f, col[2] + shadetop),
|
||||
.color_inner1[3] = !filled ? 0.0f : 1.0f,
|
||||
.color_inner2[0] = !filled ? 0.0f : max_ff(0.0f, col[0] + shadedown),
|
||||
.color_inner2[1] = !filled ? 0.0f : max_ff(0.0f, col[1] + shadedown),
|
||||
.color_inner2[2] = !filled ? 0.0f : max_ff(0.0f, col[2] + shadedown),
|
||||
.color_inner2[3] = !filled ? 0.0f : 1.0f,
|
||||
/* TODO: non-filled box don't have gradients. Just use middle color. */
|
||||
.color_outline[0] = clamp_f(col[0] + shadetop + shadedown, 0.0f, 1.0f),
|
||||
.color_outline[1] = clamp_f(col[1] + shadetop + shadedown, 0.0f, 1.0f),
|
||||
.color_outline[2] = clamp_f(col[2] + shadetop + shadedown, 0.0f, 1.0f),
|
||||
.color_outline[3] = clamp_f(col[3] + shadetop + shadedown, 0.0f, 1.0f),
|
||||
.alpha_discard = 1.0f,
|
||||
};
|
||||
|
||||
GPUBatch *batch = ui_batch_roundbox_get(filled, false);
|
||||
GPUBatch *batch = ui_batch_roundbox_widget_get();
|
||||
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
|
||||
GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params);
|
||||
GPU_batch_draw(batch);
|
||||
|
@ -2678,7 +2706,6 @@ void ui_draw_dropshadow(
|
|||
GPU_batch_draw(batch);
|
||||
|
||||
/* outline emphasis */
|
||||
GPU_line_smooth(true);
|
||||
float color[4] = {0.0f, 0.0f, 0.0f, 0.4f};
|
||||
UI_draw_roundbox_4fv(false,
|
||||
rct->xmin - 0.5f,
|
||||
|
@ -2687,7 +2714,6 @@ void ui_draw_dropshadow(
|
|||
rct->ymax + 0.5f,
|
||||
radius + 0.5f,
|
||||
color);
|
||||
GPU_line_smooth(false);
|
||||
|
||||
GPU_blend(false);
|
||||
}
|
||||
|
|
|
@ -848,6 +848,8 @@ typedef struct uiWidgetBaseParameters {
|
|||
* The absolute value itself is the discard factor.
|
||||
* Initialize value to 1.0.f if you don't want discard */
|
||||
float alpha_discard;
|
||||
float tria_type;
|
||||
float _pad[3];
|
||||
} uiWidgetBaseParameters;
|
||||
|
||||
enum {
|
||||
|
@ -861,8 +863,7 @@ enum {
|
|||
ROUNDBOX_TRIA_MAX, /* don't use */
|
||||
};
|
||||
|
||||
struct GPUBatch *ui_batch_roundbox_get(bool filled, bool antialiased);
|
||||
struct GPUBatch *ui_batch_roundbox_widget_get(int tria);
|
||||
struct GPUBatch *ui_batch_roundbox_widget_get(void);
|
||||
struct GPUBatch *ui_batch_roundbox_shadow_get(void);
|
||||
|
||||
void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4]);
|
||||
|
|
|
@ -393,35 +393,14 @@ static const uint g_shape_preset_hold_action_face[2][3] = {{2, 0, 1}, {3, 5, 4}}
|
|||
*
|
||||
* \{ */
|
||||
|
||||
/* offset in triavec[] in shader per type */
|
||||
static const int tria_ofs[ROUNDBOX_TRIA_MAX] = {
|
||||
[ROUNDBOX_TRIA_NONE] = 0,
|
||||
[ROUNDBOX_TRIA_ARROWS] = 0,
|
||||
[ROUNDBOX_TRIA_SCROLL] = 12,
|
||||
[ROUNDBOX_TRIA_MENU] = 28,
|
||||
[ROUNDBOX_TRIA_CHECK] = 34,
|
||||
[ROUNDBOX_TRIA_HOLD_ACTION_ARROW] = 40,
|
||||
};
|
||||
static const int tria_vcount[ROUNDBOX_TRIA_MAX] = {
|
||||
[ROUNDBOX_TRIA_NONE] = 0,
|
||||
[ROUNDBOX_TRIA_ARROWS] = 6,
|
||||
[ROUNDBOX_TRIA_SCROLL] = 16,
|
||||
[ROUNDBOX_TRIA_MENU] = 6,
|
||||
[ROUNDBOX_TRIA_CHECK] = 6,
|
||||
[ROUNDBOX_TRIA_HOLD_ACTION_ARROW] = 3,
|
||||
};
|
||||
|
||||
static struct {
|
||||
GPUBatch *roundbox_widget[ROUNDBOX_TRIA_MAX];
|
||||
|
||||
GPUBatch *roundbox_simple;
|
||||
GPUBatch *roundbox_simple_aa;
|
||||
GPUBatch *roundbox_simple_outline;
|
||||
GPUBatch *roundbox_widget;
|
||||
GPUBatch *roundbox_shadow;
|
||||
|
||||
/* TODO remove */
|
||||
GPUVertFormat format;
|
||||
uint vflag_id;
|
||||
} g_ui_batch_cache = {{0}};
|
||||
} g_ui_batch_cache = {0};
|
||||
|
||||
static GPUVertFormat *vflag_format(void)
|
||||
{
|
||||
|
@ -436,7 +415,7 @@ static GPUVertFormat *vflag_format(void)
|
|||
#define INNER 0
|
||||
#define OUTLINE 1
|
||||
#define EMBOSS 2
|
||||
#define NO_AA WIDGET_AA_JITTER
|
||||
#define NO_AA 0
|
||||
|
||||
static void set_roundbox_vertex_data(GPUVertBufRaw *vflag_step, uint32_t d)
|
||||
{
|
||||
|
@ -462,176 +441,30 @@ static uint32_t set_roundbox_vertex(GPUVertBufRaw *vflag_step,
|
|||
return *data;
|
||||
}
|
||||
|
||||
static uint32_t set_tria_vertex(
|
||||
GPUVertBufRaw *vflag_step, int tria_type, int tria_v, int tria_id, int jit_v)
|
||||
GPUBatch *ui_batch_roundbox_widget_get(void)
|
||||
{
|
||||
uint32_t *data = GPU_vertbuf_raw_step(vflag_step);
|
||||
if (ELEM(tria_type, ROUNDBOX_TRIA_ARROWS)) {
|
||||
tria_v += tria_id * tria_vcount[ROUNDBOX_TRIA_ARROWS];
|
||||
}
|
||||
*data = tria_ofs[tria_type] + tria_v;
|
||||
*data |= jit_v << 6;
|
||||
*data |= (tria_id == 0) ? (1 << 10) : 0; /* is first tria */
|
||||
*data |= 1 << 14; /* is tria vert */
|
||||
return *data;
|
||||
}
|
||||
|
||||
static void roundbox_batch_add_tria(GPUVertBufRaw *vflag_step, int tria, uint32_t last_data)
|
||||
{
|
||||
const int tria_num =
|
||||
ELEM(tria, ROUNDBOX_TRIA_CHECK, ROUNDBOX_TRIA_HOLD_ACTION_ARROW, ROUNDBOX_TRIA_MENU) ? 1 : 2;
|
||||
/* for each tria */
|
||||
for (int t = 0; t < tria_num; t++) {
|
||||
for (int j = 0; j < WIDGET_AA_JITTER; j++) {
|
||||
/* restart */
|
||||
set_roundbox_vertex_data(vflag_step, last_data);
|
||||
set_tria_vertex(vflag_step, tria, 0, t, j);
|
||||
for (int v = 0; v < tria_vcount[tria]; v++) {
|
||||
last_data = set_tria_vertex(vflag_step, tria, v, t, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GPUBatch *ui_batch_roundbox_widget_get(int tria)
|
||||
{
|
||||
if (g_ui_batch_cache.roundbox_widget[tria] == NULL) {
|
||||
uint32_t last_data;
|
||||
GPUVertBufRaw vflag_step;
|
||||
if (g_ui_batch_cache.roundbox_widget == NULL) {
|
||||
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(vflag_format());
|
||||
int vcount = WIDGET_SIZE_MAX; /* inner */
|
||||
vcount += 2; /* restart */
|
||||
vcount += ((WIDGET_SIZE_MAX + 1) * 2) * WIDGET_AA_JITTER; /* outline (edges) */
|
||||
vcount += 2; /* restart */
|
||||
vcount += ((WIDGET_CURVE_RESOLU * 2) * 2) * WIDGET_AA_JITTER; /* emboss */
|
||||
if (tria) {
|
||||
vcount += (tria_vcount[tria] + 2) * WIDGET_AA_JITTER; /* tria1 */
|
||||
if (!ELEM(tria, ROUNDBOX_TRIA_CHECK, ROUNDBOX_TRIA_HOLD_ACTION_ARROW, ROUNDBOX_TRIA_MENU)) {
|
||||
vcount += (tria_vcount[tria] + 2) * WIDGET_AA_JITTER; /* tria2 */
|
||||
}
|
||||
}
|
||||
GPU_vertbuf_data_alloc(vbo, vcount);
|
||||
GPU_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step);
|
||||
/* Inner */
|
||||
for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) {
|
||||
for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU - 1; a2 >= 0; a1++, a2--) {
|
||||
last_data = set_roundbox_vertex(&vflag_step, c1, a1, NO_AA, true, false, INNER);
|
||||
last_data = set_roundbox_vertex(&vflag_step, c2, a2, NO_AA, true, false, INNER);
|
||||
}
|
||||
}
|
||||
/* restart */
|
||||
set_roundbox_vertex_data(&vflag_step, last_data);
|
||||
set_roundbox_vertex(&vflag_step, 0, 0, 0, true, false, OUTLINE);
|
||||
/* Outlines */
|
||||
for (int j = 0; j < WIDGET_AA_JITTER; j++) {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
|
||||
set_roundbox_vertex(&vflag_step, c, a, j, true, false, OUTLINE);
|
||||
set_roundbox_vertex(&vflag_step, c, a, j, false, false, OUTLINE);
|
||||
}
|
||||
}
|
||||
/* Close the loop. */
|
||||
set_roundbox_vertex(&vflag_step, 0, 0, j, true, false, OUTLINE);
|
||||
last_data = set_roundbox_vertex(&vflag_step, 0, 0, j, false, false, OUTLINE);
|
||||
}
|
||||
/* restart */
|
||||
set_roundbox_vertex_data(&vflag_step, last_data);
|
||||
set_roundbox_vertex(&vflag_step, 0, 0, 0, false, false, EMBOSS);
|
||||
/* Emboss */
|
||||
/* go back and forth : avoid degenerate triangle (but beware of backface cull) */
|
||||
bool rev = false;
|
||||
for (int j = 0; j < WIDGET_AA_JITTER; j++, rev = !rev) {
|
||||
for (int c = (rev) ? 1 : 0; (rev) ? c >= 0 : c < 2; (rev) ? c-- : c++) {
|
||||
int sta = (rev) ? WIDGET_CURVE_RESOLU - 1 : 0;
|
||||
int end = WIDGET_CURVE_RESOLU;
|
||||
for (int a = sta; (rev) ? a >= 0 : a < end; (rev) ? a-- : a++) {
|
||||
set_roundbox_vertex(&vflag_step, c, a, j, false, false, EMBOSS);
|
||||
last_data = set_roundbox_vertex(&vflag_step, c, a, j, false, true, EMBOSS);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tria) {
|
||||
roundbox_batch_add_tria(&vflag_step, tria, last_data);
|
||||
}
|
||||
g_ui_batch_cache.roundbox_widget[tria] = GPU_batch_create_ex(
|
||||
GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
|
||||
gpu_batch_presets_register(g_ui_batch_cache.roundbox_widget[tria]);
|
||||
|
||||
GPU_vertbuf_data_alloc(vbo, 12);
|
||||
|
||||
GPUIndexBufBuilder ibuf;
|
||||
GPU_indexbuf_init(&ibuf, GPU_PRIM_TRIS, 6, 12);
|
||||
/* Widget */
|
||||
GPU_indexbuf_add_tri_verts(&ibuf, 0, 1, 2);
|
||||
GPU_indexbuf_add_tri_verts(&ibuf, 2, 1, 3);
|
||||
/* Trias */
|
||||
GPU_indexbuf_add_tri_verts(&ibuf, 4, 5, 6);
|
||||
GPU_indexbuf_add_tri_verts(&ibuf, 6, 5, 7);
|
||||
|
||||
GPU_indexbuf_add_tri_verts(&ibuf, 8, 9, 10);
|
||||
GPU_indexbuf_add_tri_verts(&ibuf, 10, 9, 11);
|
||||
|
||||
g_ui_batch_cache.roundbox_widget = GPU_batch_create_ex(
|
||||
GPU_PRIM_TRIS, vbo, GPU_indexbuf_build(&ibuf), GPU_BATCH_OWNS_INDEX | GPU_BATCH_OWNS_VBO);
|
||||
gpu_batch_presets_register(g_ui_batch_cache.roundbox_widget);
|
||||
}
|
||||
return g_ui_batch_cache.roundbox_widget[tria];
|
||||
}
|
||||
|
||||
GPUBatch *ui_batch_roundbox_get(bool filled, bool antialiased)
|
||||
{
|
||||
GPUBatch **batch = NULL;
|
||||
|
||||
if (filled) {
|
||||
if (antialiased) {
|
||||
batch = &g_ui_batch_cache.roundbox_simple_aa;
|
||||
}
|
||||
else {
|
||||
batch = &g_ui_batch_cache.roundbox_simple;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (antialiased) {
|
||||
BLI_assert(0); /* Use GL_LINE_SMOOTH instead!!: */
|
||||
}
|
||||
else {
|
||||
batch = &g_ui_batch_cache.roundbox_simple_outline;
|
||||
}
|
||||
}
|
||||
|
||||
if (*batch == NULL) {
|
||||
uint32_t last_data;
|
||||
GPUVertBufRaw vflag_step;
|
||||
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(vflag_format());
|
||||
int vcount = WIDGET_SIZE_MAX;
|
||||
vcount += (filled) ? 2 : 0;
|
||||
vcount *= (antialiased) ? WIDGET_AA_JITTER : 1;
|
||||
GPU_vertbuf_data_alloc(vbo, vcount);
|
||||
GPU_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step);
|
||||
|
||||
if (filled) {
|
||||
for (int j = 0; j < WIDGET_AA_JITTER; j++) {
|
||||
if (!antialiased) {
|
||||
j = NO_AA;
|
||||
}
|
||||
/* restart */
|
||||
set_roundbox_vertex(&vflag_step, 0, 0, j, true, false, INNER);
|
||||
for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) {
|
||||
for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU - 1; a2 >= 0; a1++, a2--) {
|
||||
last_data = set_roundbox_vertex(&vflag_step, c1, a1, j, true, false, INNER);
|
||||
last_data = set_roundbox_vertex(&vflag_step, c2, a2, j, true, false, INNER);
|
||||
}
|
||||
}
|
||||
/* restart */
|
||||
set_roundbox_vertex_data(&vflag_step, last_data);
|
||||
if (!antialiased) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*batch = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
|
||||
}
|
||||
else {
|
||||
for (int j = 0; j < WIDGET_AA_JITTER; j++) {
|
||||
if (!antialiased) {
|
||||
j = NO_AA;
|
||||
}
|
||||
for (int c = 0; c < 4; c++) {
|
||||
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
|
||||
set_roundbox_vertex(&vflag_step, c, a, j, true, false, INNER);
|
||||
}
|
||||
}
|
||||
if (!antialiased) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*batch = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vbo, NULL, GPU_BATCH_OWNS_VBO);
|
||||
}
|
||||
|
||||
gpu_batch_presets_register(*batch);
|
||||
}
|
||||
return *batch;
|
||||
return g_ui_batch_cache.roundbox_widget;
|
||||
}
|
||||
|
||||
GPUBatch *ui_batch_roundbox_shadow_get(void)
|
||||
|
@ -1314,14 +1147,13 @@ static void widgetbase_set_uniform_colors_ubv(uiWidgetBase *wtb,
|
|||
|
||||
/* keep in sync with shader */
|
||||
#define MAX_WIDGET_BASE_BATCH 6
|
||||
#define MAX_WIDGET_PARAMETERS 11
|
||||
#define MAX_WIDGET_PARAMETERS 12
|
||||
|
||||
static struct {
|
||||
GPUBatch *batch; /* Batch type */
|
||||
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH];
|
||||
int count;
|
||||
bool enabled;
|
||||
} g_widget_base_batch = {0};
|
||||
} g_widget_base_batch = {{{{0}}}};
|
||||
|
||||
void UI_widgetbase_draw_cache_flush(void)
|
||||
{
|
||||
|
@ -1332,7 +1164,7 @@ void UI_widgetbase_draw_cache_flush(void)
|
|||
return;
|
||||
}
|
||||
|
||||
GPUBatch *batch = g_widget_base_batch.batch;
|
||||
GPUBatch *batch = ui_batch_roundbox_widget_get();
|
||||
if (g_widget_base_batch.count == 1) {
|
||||
/* draw single */
|
||||
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
|
||||
|
@ -1376,31 +1208,15 @@ void UI_widgetbase_draw_cache_end(void)
|
|||
GPU_blend(false);
|
||||
}
|
||||
|
||||
static void draw_widgetbase_batch(GPUBatch *batch, uiWidgetBase *wtb)
|
||||
static void draw_widgetbase_batch(uiWidgetBase *wtb)
|
||||
{
|
||||
wtb->uniform_params.tria_type = wtb->tria1.type;
|
||||
wtb->uniform_params.tria1_size = wtb->tria1.size;
|
||||
wtb->uniform_params.tria2_size = wtb->tria2.size;
|
||||
copy_v2_v2(wtb->uniform_params.tria1_center, wtb->tria1.center);
|
||||
copy_v2_v2(wtb->uniform_params.tria2_center, wtb->tria2.center);
|
||||
|
||||
if (g_widget_base_batch.enabled) {
|
||||
if (g_widget_base_batch.batch == NULL) {
|
||||
g_widget_base_batch.batch = ui_batch_roundbox_widget_get(ROUNDBOX_TRIA_ARROWS);
|
||||
}
|
||||
|
||||
/* draw multi */
|
||||
if (batch != g_ui_batch_cache.roundbox_widget[ROUNDBOX_TRIA_NONE] &&
|
||||
batch != g_widget_base_batch.batch) {
|
||||
/* issue previous calls before changing batch type. */
|
||||
UI_widgetbase_draw_cache_flush();
|
||||
g_widget_base_batch.batch = batch;
|
||||
}
|
||||
|
||||
/* No need to change batch if tria is not visible. Just scale it to 0. */
|
||||
if (batch == g_ui_batch_cache.roundbox_widget[ROUNDBOX_TRIA_NONE]) {
|
||||
wtb->uniform_params.tria1_size = wtb->uniform_params.tria2_size = 0;
|
||||
}
|
||||
|
||||
g_widget_base_batch.params[g_widget_base_batch.count] = wtb->uniform_params;
|
||||
g_widget_base_batch.count++;
|
||||
|
||||
|
@ -1412,6 +1228,7 @@ static void draw_widgetbase_batch(GPUBatch *batch, uiWidgetBase *wtb)
|
|||
const float checker_params[3] = {
|
||||
UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f};
|
||||
/* draw single */
|
||||
GPUBatch *batch = ui_batch_roundbox_widget_get();
|
||||
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
|
||||
GPU_batch_uniform_4fv_array(
|
||||
batch, "parameters", MAX_WIDGET_PARAMETERS, (float *)&wtb->uniform_params);
|
||||
|
@ -1434,8 +1251,6 @@ static void widgetbase_draw_ex(uiWidgetBase *wtb,
|
|||
show_alpha_checkers = false;
|
||||
}
|
||||
|
||||
GPU_blend(true);
|
||||
|
||||
/* backdrop non AA */
|
||||
if (wtb->draw_inner) {
|
||||
if (wcol->shaded == 0) {
|
||||
|
@ -1455,7 +1270,7 @@ static void widgetbase_draw_ex(uiWidgetBase *wtb,
|
|||
outline_col[0] = wcol->outline[0];
|
||||
outline_col[1] = wcol->outline[1];
|
||||
outline_col[2] = wcol->outline[2];
|
||||
outline_col[3] = wcol->outline[3] / WIDGET_AA_JITTER;
|
||||
outline_col[3] = wcol->outline[3];
|
||||
|
||||
/* emboss bottom shadow */
|
||||
if (wtb->draw_emboss) {
|
||||
|
@ -1467,7 +1282,7 @@ static void widgetbase_draw_ex(uiWidgetBase *wtb,
|
|||
tria_col[0] = wcol->item[0];
|
||||
tria_col[1] = wcol->item[1];
|
||||
tria_col[2] = wcol->item[2];
|
||||
tria_col[3] = (uchar)((float)wcol->item[3] / WIDGET_AA_JITTER);
|
||||
tria_col[3] = wcol->item[3];
|
||||
}
|
||||
|
||||
/* Draw everything in one drawcall */
|
||||
|
@ -1476,11 +1291,10 @@ static void widgetbase_draw_ex(uiWidgetBase *wtb,
|
|||
widgetbase_set_uniform_colors_ubv(
|
||||
wtb, inner_col1, inner_col2, outline_col, emboss_col, tria_col, show_alpha_checkers);
|
||||
|
||||
GPUBatch *roundbox_batch = ui_batch_roundbox_widget_get(wtb->tria1.type);
|
||||
draw_widgetbase_batch(roundbox_batch, wtb);
|
||||
GPU_blend(true);
|
||||
draw_widgetbase_batch(wtb);
|
||||
GPU_blend(false);
|
||||
}
|
||||
|
||||
GPU_blend(false);
|
||||
}
|
||||
|
||||
static void widgetbase_draw(uiWidgetBase *wtb, const uiWidgetColors *wcol)
|
||||
|
|
|
@ -1,11 +1,62 @@
|
|||
uniform vec3 checkerColorAndSize;
|
||||
|
||||
noperspective in vec4 finalColor;
|
||||
noperspective in vec2 uvInterp;
|
||||
noperspective in float butCo;
|
||||
flat in float discardFac;
|
||||
flat in float shadeTri;
|
||||
flat in vec2 outRectSize;
|
||||
flat in vec4 outRoundCorners;
|
||||
noperspective in vec4 innerColor;
|
||||
flat in vec4 borderColor;
|
||||
flat in vec4 embossColor;
|
||||
flat in float lineWidth;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
vec3 compute_masks(vec2 uv)
|
||||
{
|
||||
bool upper_half = uv.y > outRectSize.y * 0.5;
|
||||
bool right_half = uv.x > outRectSize.x * 0.5;
|
||||
float corner_rad;
|
||||
|
||||
vec2 uv_sdf = uv;
|
||||
if (right_half) {
|
||||
uv_sdf.x = outRectSize.x - uv_sdf.x;
|
||||
}
|
||||
if (upper_half) {
|
||||
uv_sdf.y = outRectSize.y - uv_sdf.y;
|
||||
corner_rad = right_half ? outRoundCorners.z : outRoundCorners.w;
|
||||
}
|
||||
else {
|
||||
corner_rad = right_half ? outRoundCorners.y : outRoundCorners.x;
|
||||
}
|
||||
|
||||
/* Signed distance field from the corner (in pixel).
|
||||
* inner_sdf is sharp and outer_sdf is rounded. */
|
||||
uv_sdf -= corner_rad;
|
||||
float inner_sdf = max(0.0, min(uv_sdf.x, uv_sdf.y));
|
||||
float outer_sdf = -length(min(uv_sdf, 0.0));
|
||||
float sdf = inner_sdf + outer_sdf + corner_rad;
|
||||
|
||||
/* Fade emboss at the border. */
|
||||
float emboss_size = clamp((upper_half) ? 0.0 : (uv.x / corner_rad), 0.0, 1.0);
|
||||
|
||||
/* Clamp line width to be at least 1px wide. This can happen if the projection matrix
|
||||
* has been scaled (i.e: Node editor)... */
|
||||
float line_width = (lineWidth > 0.0) ? max(fwidth(uv.x), lineWidth) : 0.0;
|
||||
|
||||
const float aa_radius = 0.5;
|
||||
vec3 masks;
|
||||
masks.x = smoothstep(-aa_radius, aa_radius, sdf);
|
||||
masks.y = smoothstep(-aa_radius, aa_radius, sdf - line_width);
|
||||
masks.z = smoothstep(-aa_radius, aa_radius, sdf + line_width * emboss_size);
|
||||
|
||||
/* Compose masks together to avoid having too much alpha. */
|
||||
masks.zx = max(vec2(0.0), masks.zx - masks.xy);
|
||||
|
||||
return masks;
|
||||
}
|
||||
|
||||
vec4 do_checkerboard()
|
||||
{
|
||||
float size = checkerColorAndSize.z;
|
||||
|
@ -25,16 +76,32 @@ void main()
|
|||
discard;
|
||||
}
|
||||
|
||||
fragColor = finalColor;
|
||||
|
||||
if (butCo > 0.5) {
|
||||
vec4 checker = do_checkerboard();
|
||||
fragColor = mix(checker, fragColor, fragColor.a);
|
||||
}
|
||||
vec3 masks = compute_masks(uvInterp);
|
||||
|
||||
if (butCo > 0.0) {
|
||||
/* Alpha checker widget. */
|
||||
if (butCo > 0.5) {
|
||||
vec4 checker = do_checkerboard();
|
||||
fragColor = mix(checker, innerColor, innerColor.a);
|
||||
}
|
||||
else {
|
||||
/* Set alpha to 1.0. */
|
||||
fragColor = innerColor;
|
||||
}
|
||||
fragColor.a = 1.0;
|
||||
}
|
||||
else {
|
||||
/* Premultiply here. */
|
||||
fragColor = innerColor * vec4(innerColor.aaa, 1.0);
|
||||
}
|
||||
fragColor *= masks.y;
|
||||
fragColor += masks.x * borderColor;
|
||||
fragColor += masks.z * embossColor;
|
||||
|
||||
/* Un-premult because the blend equation is already doing the mult. */
|
||||
if (fragColor.a > 0.0) {
|
||||
fragColor.rgb /= fragColor.a;
|
||||
}
|
||||
|
||||
fragColor = blender_srgb_to_framebuffer_space(fragColor);
|
||||
}
|
||||
|
|
|
@ -1,127 +1,7 @@
|
|||
#define BIT_RANGE(x) uint((1 << x) - 1)
|
||||
|
||||
/* 2 bits for corner */
|
||||
/* Attention! Not the same order as in UI_interface.h!
|
||||
* Ordered by drawing order. */
|
||||
#define BOTTOM_LEFT 0u
|
||||
#define BOTTOM_RIGHT 1u
|
||||
#define TOP_RIGHT 2u
|
||||
#define TOP_LEFT 3u
|
||||
#define CNR_FLAG_RANGE BIT_RANGE(2)
|
||||
|
||||
/* 4bits for corner id */
|
||||
#define CORNER_VEC_OFS 2u
|
||||
#define CORNER_VEC_RANGE BIT_RANGE(4)
|
||||
const vec2 cornervec[9] = vec2[9](vec2(0.0, 1.0),
|
||||
vec2(0.02, 0.805),
|
||||
vec2(0.067, 0.617),
|
||||
vec2(0.169, 0.45),
|
||||
vec2(0.293, 0.293),
|
||||
vec2(0.45, 0.169),
|
||||
vec2(0.617, 0.076),
|
||||
vec2(0.805, 0.02),
|
||||
vec2(1.0, 0.0));
|
||||
|
||||
/* 4bits for jitter id */
|
||||
#define JIT_OFS 6u
|
||||
#define JIT_RANGE BIT_RANGE(4)
|
||||
const vec2 jit[9] = vec2[9](vec2(0.468813, -0.481430),
|
||||
vec2(-0.155755, -0.352820),
|
||||
vec2(0.219306, -0.238501),
|
||||
vec2(-0.393286, -0.110949),
|
||||
vec2(-0.024699, 0.013908),
|
||||
vec2(0.343805, 0.147431),
|
||||
vec2(-0.272855, 0.269918),
|
||||
vec2(0.095909, 0.388710),
|
||||
vec2(0.0, 0.0));
|
||||
|
||||
/* 2bits for other flags */
|
||||
#define INNER_FLAG uint(1 << 10) /* is inner vert */
|
||||
#define EMBOSS_FLAG uint(1 << 11) /* is emboss vert */
|
||||
|
||||
/* 2bits for color */
|
||||
#define COLOR_OFS 12u
|
||||
#define COLOR_RANGE BIT_RANGE(2)
|
||||
#define COLOR_INNER 0u
|
||||
#define COLOR_EDGE 1u
|
||||
#define COLOR_EMBOSS 2u
|
||||
|
||||
/* 2bits for trias type */
|
||||
#define TRIA_FLAG uint(1 << 14) /* is tria vert */
|
||||
#define TRIA_FIRST INNER_FLAG /* is first tria (reuse INNER_FLAG) */
|
||||
|
||||
/* We can reuse the CORNER_* bits for tria */
|
||||
#define TRIA_VEC_RANGE BIT_RANGE(6)
|
||||
|
||||
/* Some GPUs have performanse issues with this array being const (Doesn't fit in the registers?).
|
||||
* To resolve this issue, store the array as a uniform buffer.
|
||||
* (The array is still stored in the registry, but indexing is done in the uniform buffer.) */
|
||||
uniform vec2 triavec[43] = vec2[43](
|
||||
|
||||
/* ROUNDBOX_TRIA_ARROWS */
|
||||
vec2(-0.170000, 0.400000),
|
||||
vec2(-0.050000, 0.520000),
|
||||
vec2(0.250000, 0.000000),
|
||||
vec2(0.470000, -0.000000),
|
||||
vec2(-0.170000, -0.400000),
|
||||
vec2(-0.050000, -0.520000),
|
||||
vec2(0.170000, 0.400000),
|
||||
vec2(0.050000, 0.520000),
|
||||
vec2(-0.250000, 0.000000),
|
||||
vec2(-0.470000, -0.000000),
|
||||
vec2(0.170000, -0.400000),
|
||||
vec2(0.050000, -0.520000),
|
||||
|
||||
/* ROUNDBOX_TRIA_SCROLL - circle tria (triangle strip) */
|
||||
vec2(0.000000, 1.000000),
|
||||
vec2(0.382684, 0.923879),
|
||||
vec2(-0.382683, 0.923880),
|
||||
vec2(0.707107, 0.707107),
|
||||
vec2(-0.707107, 0.707107),
|
||||
vec2(0.923879, 0.382684),
|
||||
vec2(-0.923879, 0.382684),
|
||||
vec2(1.000000, 0.000000),
|
||||
vec2(-1.000000, 0.000000),
|
||||
vec2(0.923879, -0.382684),
|
||||
vec2(-0.923879, -0.382684),
|
||||
vec2(0.707107, -0.707107),
|
||||
vec2(-0.707107, -0.707107),
|
||||
vec2(0.382684, -0.923879),
|
||||
vec2(-0.382683, -0.923880),
|
||||
vec2(0.000000, -1.000000),
|
||||
|
||||
/* ROUNDBOX_TRIA_MENU - menu arrows */
|
||||
vec2(-0.51, 0.07),
|
||||
vec2(-0.4, 0.18),
|
||||
vec2(-0.05, -0.39),
|
||||
vec2(-0.05, -0.17),
|
||||
vec2(0.41, 0.07),
|
||||
vec2(0.3, 0.18),
|
||||
|
||||
/* ROUNDBOX_TRIA_CHECK - check mark */
|
||||
vec2(-0.67000, 0.020000),
|
||||
vec2(-0.500000, 0.190000),
|
||||
vec2(-0.130000, -0.520000),
|
||||
vec2(-0.130000, -0.170000),
|
||||
vec2(0.720000, 0.430000),
|
||||
vec2(0.530000, 0.590000),
|
||||
|
||||
/* ROUNDBOX_TRIA_HOLD_ACTION_ARROW - hold action arrows */
|
||||
#define OX (-0.32)
|
||||
#define OY (0.1)
|
||||
#define SC (0.35 * 2)
|
||||
// vec2(-0.5 + SC, 1.0 + OY), vec2( 0.5, 1.0 + OY), vec2( 0.5, 0.0 + OY + SC),
|
||||
vec2((0.5 - SC) + OX, 1.0 + OY),
|
||||
vec2(-0.5 + OX, 1.0 + OY),
|
||||
vec2(-0.5 + OX, SC + OY)
|
||||
#undef OX
|
||||
#undef OY
|
||||
#undef SC
|
||||
);
|
||||
|
||||
uniform mat4 ModelViewProjectionMatrix;
|
||||
|
||||
#define MAX_PARAM 11
|
||||
#define MAX_PARAM 12
|
||||
#ifdef USE_INSTANCE
|
||||
# define MAX_INSTANCE 6
|
||||
uniform vec4 parameters[MAX_PARAM * MAX_INSTANCE];
|
||||
|
@ -147,105 +27,152 @@ uniform vec4 parameters[MAX_PARAM];
|
|||
#define tria2Size parameters[gl_InstanceID * MAX_PARAM + 10].y
|
||||
#define shadeDir parameters[gl_InstanceID * MAX_PARAM + 10].z
|
||||
#define alphaDiscard parameters[gl_InstanceID * MAX_PARAM + 10].w
|
||||
#define triaType parameters[gl_InstanceID * MAX_PARAM + 11].x
|
||||
|
||||
/* We encode alpha check and discard factor together. */
|
||||
#define doAlphaCheck (alphaDiscard < 0.0)
|
||||
#define discardFactor abs(alphaDiscard)
|
||||
|
||||
in uint vflag;
|
||||
|
||||
noperspective out vec4 finalColor;
|
||||
noperspective out vec2 uvInterp;
|
||||
flat out vec2 outRectSize;
|
||||
flat out vec4 outRoundCorners;
|
||||
noperspective out vec4 innerColor;
|
||||
flat out vec4 borderColor;
|
||||
flat out vec4 embossColor;
|
||||
flat out float lineWidth;
|
||||
noperspective out float butCo;
|
||||
flat out float discardFac;
|
||||
|
||||
vec2 do_widget(void)
|
||||
{
|
||||
uint cflag = vflag & CNR_FLAG_RANGE;
|
||||
uint vofs = (vflag >> CORNER_VEC_OFS) & CORNER_VEC_RANGE;
|
||||
bool is_inner = (vflag & INNER_FLAG) != 0u;
|
||||
lineWidth = abs(rect.x - recti.x);
|
||||
vec2 emboss_ofs = vec2(0.0, -lineWidth);
|
||||
vec2 v_pos[4] = vec2[4](rect.xz + emboss_ofs, rect.xw, rect.yz + emboss_ofs, rect.yw);
|
||||
vec2 pos = v_pos[gl_VertexID];
|
||||
|
||||
vec2 v = cornervec[vofs];
|
||||
/* Scale by corner radius */
|
||||
v *= roundCorners[cflag] * ((is_inner) ? radsi : rads);
|
||||
/* Flip in the right direction and osition to corner */
|
||||
vec4 rct = (is_inner) ? recti : rect;
|
||||
if (cflag == BOTTOM_LEFT) {
|
||||
v += rct.xz;
|
||||
}
|
||||
else if (cflag == BOTTOM_RIGHT) {
|
||||
v = vec2(-v.y, v.x);
|
||||
v += rct.yz;
|
||||
}
|
||||
else if (cflag == TOP_RIGHT) {
|
||||
v = -v;
|
||||
v += rct.yw;
|
||||
}
|
||||
else /* (cflag == TOP_LEFT) */ {
|
||||
v = vec2(v.y, -v.x);
|
||||
v += rct.xw;
|
||||
}
|
||||
uvInterp = pos - rect.xz;
|
||||
outRectSize = rect.yw - rect.xz;
|
||||
outRoundCorners = rads * roundCorners;
|
||||
|
||||
vec2 uv = faci * (v - recti.xz);
|
||||
|
||||
/* compute uv and color gradient */
|
||||
uint color_id = (vflag >> COLOR_OFS) & COLOR_RANGE;
|
||||
if (color_id == COLOR_INNER) {
|
||||
float fac = clamp((shadeDir > 0.0) ? uv.y : uv.x, 0.0, 1.0);
|
||||
|
||||
if (doAlphaCheck) {
|
||||
finalColor = colorInner1;
|
||||
butCo = uv.x;
|
||||
}
|
||||
else {
|
||||
finalColor = mix(colorInner2, colorInner1, fac);
|
||||
butCo = -abs(uv.x);
|
||||
}
|
||||
vec2 uv = uvInterp / outRectSize;
|
||||
float fac = clamp((shadeDir > 0.0) ? uv.y : uv.x, 0.0, 1.0);
|
||||
/* Note innerColor is premultiplied inside the fragment shader. */
|
||||
if (doAlphaCheck) {
|
||||
innerColor = colorInner1;
|
||||
butCo = uv.x;
|
||||
}
|
||||
else if (color_id == COLOR_EDGE) {
|
||||
finalColor = colorEdge;
|
||||
butCo = -abs(uv.x);
|
||||
}
|
||||
else /* (color_id == COLOR_EMBOSS) */ {
|
||||
finalColor = colorEmboss;
|
||||
else {
|
||||
innerColor = mix(colorInner2, colorInner1, fac);
|
||||
butCo = -abs(uv.x);
|
||||
}
|
||||
|
||||
bool is_emboss = (vflag & EMBOSS_FLAG) != 0u;
|
||||
v.y -= (is_emboss) ? (recti.z - rect.z) : 0.0;
|
||||
/* We need premultiplied color for transparency. */
|
||||
borderColor = colorEdge * vec4(colorEdge.aaa, 1.0);
|
||||
embossColor = colorEmboss * vec4(colorEmboss.aaa, 1.0);
|
||||
|
||||
return v;
|
||||
return pos;
|
||||
}
|
||||
|
||||
vec2 do_tria()
|
||||
{
|
||||
uint vofs = vflag & TRIA_VEC_RANGE;
|
||||
int vidx = gl_VertexID % 4;
|
||||
bool tria2 = gl_VertexID > 7;
|
||||
|
||||
vec2 v = triavec[vofs];
|
||||
vec2 pos;
|
||||
float size = (tria2) ? -tria2Size : tria1Size;
|
||||
vec2 center = (tria2) ? tria2Center : tria1Center;
|
||||
|
||||
finalColor = colorTria;
|
||||
butCo = -1.0;
|
||||
vec2 arrow_pos[4] = vec2[4](vec2(0.0, 0.6), vec2(0.6, 0.0), vec2(-0.6, 0.0), vec2(0.0, -0.6));
|
||||
/* Rotated uv space by 45deg and mirrored. */
|
||||
vec2 arrow_uvs[4] = vec2[4](vec2(0.0, 0.85), vec2(0.85, 0.85), vec2(0.0, 0.0), vec2(0.0, 0.85));
|
||||
|
||||
bool is_tria_first = (vflag & TRIA_FIRST) != 0u;
|
||||
vec2 point_pos[4] = vec2[4](vec2(-1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, -1.0), vec2(1.0, 1.0));
|
||||
vec2 point_uvs[4] = vec2[4](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 0.0), vec2(1.0, 1.0));
|
||||
|
||||
if (is_tria_first) {
|
||||
v = v * tria1Size + tria1Center;
|
||||
/* We reuse the SDF roundbox rendering of widget to render the tria shapes.
|
||||
* This means we do clever tricks to position the rectangle the way we want using
|
||||
* the 2 triangles uvs. */
|
||||
if (triaType == 0.0) {
|
||||
/* ROUNDBOX_TRIA_NONE */
|
||||
outRectSize = uvInterp = pos = vec2(0);
|
||||
outRoundCorners = vec4(0.01);
|
||||
}
|
||||
else if (triaType == 1.0) {
|
||||
/* ROUNDBOX_TRIA_ARROWS */
|
||||
pos = arrow_pos[vidx];
|
||||
uvInterp = arrow_uvs[vidx];
|
||||
uvInterp -= vec2(0.05, 0.63); /* Translate */
|
||||
outRectSize = vec2(0.74, 0.17);
|
||||
outRoundCorners = vec4(0.08);
|
||||
}
|
||||
else if (triaType == 2.0) {
|
||||
/* ROUNDBOX_TRIA_SCROLL */
|
||||
pos = point_pos[vidx];
|
||||
uvInterp = point_uvs[vidx];
|
||||
outRectSize = vec2(1.0);
|
||||
outRoundCorners = vec4(0.5);
|
||||
}
|
||||
else if (triaType == 3.0) {
|
||||
/* ROUNDBOX_TRIA_MENU */
|
||||
pos = tria2 ? vec2(0.0) : arrow_pos[vidx]; /* Solo tria */
|
||||
pos = vec2(pos.y, -pos.x); /* Rotate */
|
||||
pos += vec2(-0.05, 0.0); /* Translate */
|
||||
size *= 0.8; /* Scale */
|
||||
uvInterp = arrow_uvs[vidx];
|
||||
uvInterp -= vec2(0.05, 0.63); /* Translate */
|
||||
outRectSize = vec2(0.74, 0.17);
|
||||
outRoundCorners = vec4(0.01);
|
||||
}
|
||||
else if (triaType == 4.0) {
|
||||
/* ROUNDBOX_TRIA_CHECK */
|
||||
/* A bit more hacky: We use the two trias joined together to render
|
||||
* both sides of the checkmark with different length. */
|
||||
pos = arrow_pos[min(vidx, 2)]; /* Only keep 1 triangle. */
|
||||
pos.y = tria2 ? -pos.y : pos.y; /* Mirror along X */
|
||||
pos = pos.x * vec2(0.0872, -0.996) + pos.y * vec2(0.996, 0.0872); /* Rotate (85deg) */
|
||||
pos += vec2(-0.1, 0.2); /* Translate */
|
||||
center = tria1Center;
|
||||
size = tria1Size * 1.7; /* Scale */
|
||||
uvInterp = arrow_uvs[vidx];
|
||||
uvInterp -= tria2 ? vec2(0.4, 0.65) : vec2(0.08, 0.65); /* Translate */
|
||||
outRectSize = vec2(0.74, 0.14);
|
||||
outRoundCorners = vec4(0.01);
|
||||
}
|
||||
else {
|
||||
v = v * tria2Size + tria2Center;
|
||||
/* ROUNDBOX_TRIA_HOLD_ACTION_ARROW */
|
||||
/* We use a single triangle to cut the round rect in half. The edge will not be Antialiased. */
|
||||
pos = tria2 ? vec2(0.0) : arrow_pos[min(vidx, 2)]; /* Only keep 1 triangle. */
|
||||
pos = pos.x * vec2(0.707, 0.707) + pos.y * vec2(-0.707, 0.707); /* Rotate (45deg) */
|
||||
pos += vec2(-1.7, 2.4); /* Translate (hardcoded, might want to remove) */
|
||||
size *= 0.4; /* Scale */
|
||||
uvInterp = arrow_uvs[vidx];
|
||||
uvInterp -= vec2(0.05, 0.05); /* Translate */
|
||||
outRectSize = vec2(0.75);
|
||||
outRoundCorners = vec4(0.01);
|
||||
}
|
||||
|
||||
return v;
|
||||
uvInterp *= abs(size);
|
||||
outRectSize *= abs(size);
|
||||
outRoundCorners *= abs(size);
|
||||
|
||||
pos = pos * size + center;
|
||||
|
||||
innerColor = colorTria * vec4(colorTria.aaa, 1.0);
|
||||
|
||||
lineWidth = 0.0;
|
||||
borderColor = vec4(0.0);
|
||||
embossColor = vec4(0.0);
|
||||
|
||||
butCo = -1.0;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
discardFac = discardFactor;
|
||||
bool is_tria = (vflag & TRIA_FLAG) != 0u;
|
||||
bool is_tria = (gl_VertexID > 3);
|
||||
vec2 pos = (is_tria) ? do_tria() : do_widget();
|
||||
|
||||
vec2 v = (is_tria) ? do_tria() : do_widget();
|
||||
|
||||
/* Antialiasing offset */
|
||||
v += jit[(vflag >> JIT_OFS) & JIT_RANGE];
|
||||
|
||||
gl_Position = ModelViewProjectionMatrix * vec4(v, 0.0, 1.0);
|
||||
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue