tornavis/source/blender/gpu/shaders/gpu_shader_2D_widget_base_v...

191 lines
6.3 KiB
GLSL

/* SPDX-FileCopyrightText: 2018-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#define recti parameters[widgetID * MAX_PARAM + 0]
#define rect parameters[widgetID * MAX_PARAM + 1]
#define radsi parameters[widgetID * MAX_PARAM + 2].x
#define rads parameters[widgetID * MAX_PARAM + 2].y
#define faci parameters[widgetID * MAX_PARAM + 2].zw
#define roundCorners parameters[widgetID * MAX_PARAM + 3]
#define colorInner1 parameters[widgetID * MAX_PARAM + 4]
#define colorInner2 parameters[widgetID * MAX_PARAM + 5]
#define colorEdge parameters[widgetID * MAX_PARAM + 6]
#define colorEmboss parameters[widgetID * MAX_PARAM + 7]
#define colorTria parameters[widgetID * MAX_PARAM + 8]
#define tria1Center parameters[widgetID * MAX_PARAM + 9].xy
#define tria2Center parameters[widgetID * MAX_PARAM + 9].zw
#define tria1Size parameters[widgetID * MAX_PARAM + 10].x
#define tria2Size parameters[widgetID * MAX_PARAM + 10].y
#define shadeDir parameters[widgetID * MAX_PARAM + 10].z
#define alphaDiscard parameters[widgetID * MAX_PARAM + 10].w
#define triaType parameters[widgetID * MAX_PARAM + 11].x
/* We encode alpha check and discard factor together. */
#define doAlphaCheck (alphaDiscard < 0.0)
#define discardFactor abs(alphaDiscard)
vec2 do_widget(void)
{
/* Offset to avoid losing pixels (mimics conservative rasterization). */
const vec2 ofs = vec2(0.5, -0.5);
lineWidth = abs(rect.x - recti.x);
vec2 emboss_ofs = vec2(0.0, -lineWidth);
vec2 pos;
switch (gl_VertexID) {
default:
case 0: {
pos = rect.xz + emboss_ofs + ofs.yy;
break;
}
case 1: {
pos = rect.xw + ofs.yx;
break;
}
case 2: {
pos = rect.yz + emboss_ofs + ofs.xy;
break;
}
case 3: {
pos = rect.yw + ofs.xx;
break;
}
}
uvInterp = pos - rect.xz;
outRectSize = rect.yw - rect.xz;
outRoundCorners = rads * roundCorners;
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 {
innerColor = mix(colorInner2, colorInner1, fac);
butCo = -abs(uv.x);
}
/* We need premultiplied color for transparency. */
borderColor = colorEdge * vec4(colorEdge.aaa, 1.0);
embossColor = colorEmboss * vec4(colorEmboss.aaa, 1.0);
return pos;
}
vec2 do_tria()
{
int vidx = gl_VertexID % 4;
bool tria2 = gl_VertexID > 7;
vec2 pos = vec2(0.0);
float size = (tria2) ? -tria2Size : tria1Size;
vec2 center = (tria2) ? tria2Center : tria1Center;
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));
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));
/* We reuse the SDF round-box 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 triangles joined together to render
* both sides of the check-mark 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 if (triaType == 5.0) {
/* ROUNDBOX_TRIA_HOLD_ACTION_ARROW */
/* We use a single triangle to cut the round rect in half.
* The edge will not be Anti-aliased. */
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 (hard-coded, 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);
}
else if (triaType == 6.0) {
/* ROUNDBOX_TRIA_DASH */
pos = point_pos[vidx];
uvInterp = point_uvs[vidx];
uvInterp -= vec2(0.2, 0.45); /* Translate */
outRectSize = vec2(0.6, 0.1);
outRoundCorners = vec4(0.01);
}
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 = -2.0;
return pos;
}
void main()
{
discardFac = discardFactor;
bool is_tria = (gl_VertexID > 3);
vec2 pos = (is_tria) ? do_tria() : do_widget();
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
}