Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2019-12-02 03:40:58 +0300
committerClément Foucault <foucault.clem@gmail.com>2019-12-02 15:15:52 +0300
commit9516921c05bd9fee5c94942eb8e38f47ba7e4351 (patch)
treeda007fc17bc6a02f849dae2e8f76f5ab304fe4dc /source/blender/draw/engines/overlay/shaders
parent1f6c3699a836d485ed37f443cd0fcd19e978dbb6 (diff)
Overlay Engine: Refactor & Cleanup
This is the unification of all overlays into one overlay engine as described in T65347. I went over all the code making it more future proof with less hacks and removing old / not relevent parts. Goals / Acheivements: - Remove internal shader usage (only drw shaders) - Remove viewportSize and viewportSizeInv and put them in gloabl ubo - Fixed some drawing issues: Missing probe option and Missing Alt+B clipping of some shader - Remove old (legacy) shaders dependancy (not using view UBO). - Less shader variation (less compilation time at first load and less patching needed for vulkan) - removed some geom shaders when I could - Remove static e_data (except shaders storage where it is OK) - Clear the way to fix some anoying limitations (dithered transparency, background image compositing etc...) - Wireframe drawing now uses the same batching capabilities as workbench & eevee (indirect drawing). - Reduced complexity, removed ~3000 Lines of code in draw (also removed a lot of unused shader in GPU). - Post AA to avoid complexity and cost of MSAA. Remaining issues: - ~~Armature edits, overlay toggles, (... others?) are not refreshing viewport after AA is complete~~ - FXAA is not the best for wires, maybe investigate SMAA - Maybe do something more temporally stable for AA. - ~~Paint overlays are not working with AA.~~ - ~~infront objects are difficult to select.~~ - ~~the infront wires sometimes goes through they solid counterpart (missing clear maybe?) (toggle overlays on-off when using infront+wireframe overlay in solid shading)~~ Note: I made some decision to change slightly the appearance of some objects to simplify their drawing. Namely the empty arrows end (which is now hollow/wire) and distance points of the cameras/spots being done by lines. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D6296
Diffstat (limited to 'source/blender/draw/engines/overlay/shaders')
-rw-r--r--source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl135
-rw-r--r--source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl11
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl33
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl164
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl25
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl55
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl116
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl48
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl11
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl37
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl104
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl76
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl87
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl13
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl90
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl18
-rw-r--r--source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl14
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl114
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl18
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl29
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl31
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl32
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl38
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl8
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl35
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl76
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_frag.glsl7
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_vert.glsl23
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl46
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl88
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl53
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl25
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl97
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl19
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl42
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_frag.glsl13
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl30
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl18
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl20
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl30
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_vert.glsl227
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl31
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl40
-rw-r--r--source/blender/draw/engines/overlay/shaders/facing_frag.glsl9
-rw-r--r--source/blender/draw/engines/overlay/shaders/facing_vert.glsl12
-rw-r--r--source/blender/draw/engines/overlay/shaders/grid_frag.glsl248
-rw-r--r--source/blender/draw/engines/overlay/shaders/grid_vert.glsl52
-rw-r--r--source/blender/draw/engines/overlay/shaders/image_frag.glsl34
-rw-r--r--source/blender/draw/engines/overlay/shaders/image_vert.glsl21
-rw-r--r--source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl47
-rw-r--r--source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl96
-rw-r--r--source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl58
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl86
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_expand_frag.glsl51
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_lightprobe_grid_vert.glsl31
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl18
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl54
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl29
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_resolve_frag.glsl21
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl24
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl32
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl23
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl19
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl28
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl27
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl106
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl20
-rw-r--r--source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl38
-rw-r--r--source/blender/draw/engines/overlay/shaders/particle_frag.glsl16
-rw-r--r--source/blender/draw/engines/overlay/shaders/particle_vert.glsl68
-rw-r--r--source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl20
-rw-r--r--source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl117
-rw-r--r--source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl20
-rw-r--r--source/blender/draw/engines/overlay/shaders/wireframe_geom.glsl61
-rw-r--r--source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl144
75 files changed, 3857 insertions, 0 deletions
diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl
new file mode 100644
index 00000000000..98f69abe89f
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl
@@ -0,0 +1,135 @@
+
+uniform sampler2D colorTex;
+uniform sampler2D depthTex;
+uniform sampler2D lineTex;
+
+in vec2 uvs;
+
+out vec4 fragColor;
+
+#define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */
+
+/**
+ * We want to know how much a pixel is covered by a line.
+ * We replace the square pixel with acircle of the same area and try to find the intersection area.
+ * The area we search is the circular segment. https://en.wikipedia.org/wiki/Circular_segment
+ * The formula for the area uses inverse trig function and is quite complexe. Instead,
+ * we approximate it by using the smoothstep function and a 1.05 factor to the disc radius.
+ */
+#define DISC_RADIUS (M_1_SQRTPI * 1.05)
+#define LINE_SMOOTH_START (0.5 - DISC_RADIUS)
+#define LINE_SMOOTH_END (0.5 + DISC_RADIUS)
+
+/**
+ * Returns coverage of a line onto a sample that is distance_to_line (in pixels) far from the line.
+ * line_kernel_size is the inner size of the line with 100% coverage.
+ */
+float line_coverage(float distance_to_line, float line_kernel_size)
+{
+ return smoothstep(LINE_SMOOTH_END, LINE_SMOOTH_START, abs(distance_to_line) - line_kernel_size);
+}
+vec4 line_coverage(vec4 distance_to_line, float line_kernel_size)
+{
+ return smoothstep(LINE_SMOOTH_END, LINE_SMOOTH_START, abs(distance_to_line) - line_kernel_size);
+}
+
+vec2 decode_line_dir(vec2 dir)
+{
+ return dir * 2.0 - 1.0;
+}
+
+float decode_line_dist(float dist)
+{
+ return (dist - 0.1) * 4.0 - 2.0;
+}
+
+float neighbor_dist(vec3 line_dir_and_dist, vec2 ofs)
+{
+ float dist = decode_line_dist(line_dir_and_dist.z);
+ vec2 dir = decode_line_dir(line_dir_and_dist.xy);
+
+ bool is_line = line_dir_and_dist.z != 0.0;
+ bool dir_horiz = abs(dir.x) > abs(dir.y);
+ bool ofs_horiz = (ofs.x != 0);
+
+ if (!is_line || (ofs_horiz != dir_horiz)) {
+ dist += 1e10; /* No line. */
+ }
+ else {
+ dist += dot(ofs, -dir);
+ }
+ return dist;
+}
+
+void neighbor_blend(
+ float line_coverage, float line_depth, vec4 line_color, inout float frag_depth, inout vec4 col)
+{
+ line_color *= line_coverage;
+ if (line_coverage > 0.0 && line_depth < frag_depth) {
+ /* Alpha over. */
+ col = col * (1.0 - line_color.a) + line_color;
+ frag_depth = line_depth;
+ }
+ else {
+ /* Alpha under. */
+ col = col + line_color * (1.0 - col.a);
+ }
+}
+
+void main()
+{
+ ivec2 center_texel = ivec2(gl_FragCoord.xy);
+ const float line_kernel = 0.0;
+
+ fragColor = texelFetch(colorTex, center_texel, 0);
+
+ float depth = texelFetch(depthTex, center_texel, 0).r;
+
+ float dist_raw = texelFetch(lineTex, center_texel, 0).b;
+ float dist = decode_line_dist(dist_raw);
+
+ /* TODO Opti: use textureGather */
+ vec4 neightbor_col0 = texelFetchOffset(colorTex, center_texel, 0, ivec2(1, 0));
+ vec4 neightbor_col1 = texelFetchOffset(colorTex, center_texel, 0, ivec2(-1, 0));
+ vec4 neightbor_col2 = texelFetchOffset(colorTex, center_texel, 0, ivec2(0, 1));
+ vec4 neightbor_col3 = texelFetchOffset(colorTex, center_texel, 0, ivec2(0, -1));
+
+ vec3 neightbor_line0 = texelFetchOffset(lineTex, center_texel, 0, ivec2(1, 0)).rgb;
+ vec3 neightbor_line1 = texelFetchOffset(lineTex, center_texel, 0, ivec2(-1, 0)).rgb;
+ vec3 neightbor_line2 = texelFetchOffset(lineTex, center_texel, 0, ivec2(0, 1)).rgb;
+ vec3 neightbor_line3 = texelFetchOffset(lineTex, center_texel, 0, ivec2(0, -1)).rgb;
+
+ vec4 depths;
+ depths.x = texelFetchOffset(depthTex, center_texel, 0, ivec2(1, 0)).r;
+ depths.y = texelFetchOffset(depthTex, center_texel, 0, ivec2(-1, 0)).r;
+ depths.z = texelFetchOffset(depthTex, center_texel, 0, ivec2(0, 1)).r;
+ depths.w = texelFetchOffset(depthTex, center_texel, 0, ivec2(0, -1)).r;
+
+ vec4 line_dists;
+ line_dists.x = neighbor_dist(neightbor_line0, vec2(1, 0));
+ line_dists.y = neighbor_dist(neightbor_line1, vec2(-1, 0));
+ line_dists.z = neighbor_dist(neightbor_line2, vec2(0, 1));
+ line_dists.w = neighbor_dist(neightbor_line3, vec2(0, -1));
+
+ vec4 coverage = line_coverage(line_dists, line_kernel);
+
+ if (dist_raw > 0.0) {
+ fragColor *= line_coverage(dist, line_kernel);
+ }
+
+ /* We dont order fragments but use alpha over/alpha under based on current minimum frag depth. */
+ neighbor_blend(coverage.x, depths.x, neightbor_col0, depth, fragColor);
+ neighbor_blend(coverage.y, depths.y, neightbor_col1, depth, fragColor);
+ neighbor_blend(coverage.z, depths.z, neightbor_col2, depth, fragColor);
+ neighbor_blend(coverage.w, depths.w, neightbor_col3, depth, fragColor);
+
+#if 1
+ /* Fix aliasing issue with really dense meshes and 1 pixel sized lines. */
+ if (dist_raw > 0.0 && line_kernel < 0.45) {
+ vec4 lines = vec4(neightbor_line0.z, neightbor_line1.z, neightbor_line2.z, neightbor_line3.z);
+ /* Count number of line neighbors. */
+ float blend = dot(vec4(0.25), step(0.001, lines));
+ fragColor = mix(fragColor, fragColor / fragColor.a, blend);
+ }
+#endif
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl
new file mode 100644
index 00000000000..4f3c36c7bd7
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl
@@ -0,0 +1,11 @@
+
+out vec2 uvs;
+
+void main()
+{
+ int v = gl_VertexID % 3;
+ float x = float((v & 1) << 2);
+ float y = float((v & 2) << 1);
+ gl_Position = vec4(x - 1.0, y - 1.0, 1.0, 1.0);
+ uvs = vec2(x, y) * 0.5;
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl
new file mode 100644
index 00000000000..371229f23ab
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl
@@ -0,0 +1,33 @@
+
+/* ---- Instantiated Attrs ---- */
+in vec2 pos;
+
+/* ---- Per instance Attrs ---- */
+/* Assumed to be in world coordinate already. */
+in vec4 color;
+in mat4 inst_obmat;
+
+flat out vec4 finalColor;
+
+vec3 sphere_project(float ax, float az)
+{
+ float sine = 1.0 - ax * ax - az * az;
+ float q3 = sqrt(max(0.0, sine));
+
+ return vec3(-az * q3, 0.5 - sine, ax * q3) * 2.0;
+}
+
+void main()
+{
+ mat4 model_mat = inst_obmat;
+ model_mat[0][3] = model_mat[1][3] = model_mat[2][3] = 0.0;
+ model_mat[3][3] = 1.0;
+
+ vec2 amin = vec2(inst_obmat[0][3], inst_obmat[1][3]);
+ vec2 amax = vec2(inst_obmat[2][3], inst_obmat[3][3]);
+
+ vec3 final_pos = sphere_project(pos.x * abs((pos.x > 0.0) ? amax.x : amin.x),
+ pos.y * abs((pos.y > 0.0) ? amax.y : amin.y));
+ gl_Position = ViewProjectionMatrix * (model_mat * vec4(final_pos, 1.0));
+ finalColor = color;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl
new file mode 100644
index 00000000000..e3cc8d582d8
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl
@@ -0,0 +1,164 @@
+
+/* ---- Instantiated Attrs ---- */
+in vec2 pos0;
+in vec2 pos1;
+in vec2 pos2;
+
+/* ---- Per instance Attrs ---- */
+/* Assumed to be in world coordinate already. */
+in vec4 headSphere;
+in vec4 tailSphere;
+in vec4 outlineColorSize;
+in vec3 xAxis;
+
+flat out vec4 finalColor;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy;
+}
+
+vec2 compute_dir(vec2 v0, vec2 v1, vec2 v2)
+{
+ vec2 dir = normalize(v2 - v0);
+ dir = vec2(dir.y, -dir.x);
+ return dir;
+}
+
+mat3 compute_mat(vec4 sphere, vec3 bone_vec, out float z_ofs)
+{
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ vec3 cam_ray = (is_persp) ? sphere.xyz - ViewMatrixInverse[3].xyz : -ViewMatrixInverse[2].xyz;
+
+ /* Sphere center distance from the camera (persp) in world space. */
+ float cam_dist = length(cam_ray);
+
+ /* Compute view aligned orthonormal space. */
+ vec3 z_axis = cam_ray / cam_dist;
+ vec3 x_axis = normalize(cross(bone_vec, z_axis));
+ vec3 y_axis = cross(z_axis, x_axis);
+ z_ofs = 0.0;
+
+ if (is_persp) {
+ /* For perspective, the projected sphere radius
+ * can be bigger than the center disc. Compute the
+ * max angular size and compensate by sliding the disc
+ * towards the camera and scale it accordingly. */
+ const float half_pi = 3.1415926 * 0.5;
+ float rad = sphere.w;
+ /* Let be :
+ * V the view vector origin.
+ * O the sphere origin.
+ * T the point on the target circle.
+ * We compute the angle between (OV) and (OT). */
+ float a = half_pi - asin(rad / cam_dist);
+ float cos_b = cos(a);
+ float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0));
+
+ x_axis *= sin_b;
+ y_axis *= sin_b;
+ z_ofs = -rad * cos_b;
+ }
+
+ return mat3(x_axis, y_axis, z_axis);
+}
+
+struct Bone {
+ vec3 vec;
+ float sinb;
+};
+
+bool bone_blend_starts(vec3 p, Bone b)
+{
+ /* we just want to know when the head sphere starts interpolating. */
+ return dot(p, b.vec) > -b.sinb;
+}
+
+vec3 get_outline_point(vec2 pos,
+ vec4 sph_near,
+ vec4 sph_far,
+ mat3 mat_near,
+ mat3 mat_far,
+ float z_ofs_near,
+ float z_ofs_far,
+ Bone b)
+{
+ /* Compute outline position on the nearest sphere and check
+ * if it penetrates the capsule body. If it does, put this
+ * vertex on the farthest sphere. */
+ vec3 wpos = mat_near * vec3(pos * sph_near.w, z_ofs_near);
+ if (bone_blend_starts(wpos, b)) {
+ wpos = sph_far.xyz + mat_far * vec3(pos * sph_far.w, z_ofs_far);
+ }
+ else {
+ wpos += sph_near.xyz;
+ }
+ return wpos;
+}
+
+void main()
+{
+ float dst_head = distance(headSphere.xyz, ViewMatrixInverse[3].xyz);
+ float dst_tail = distance(tailSphere.xyz, ViewMatrixInverse[3].xyz);
+ // float dst_head = -dot(headSphere.xyz, ViewMatrix[2].xyz);
+ // float dst_tail = -dot(tailSphere.xyz, ViewMatrix[2].xyz);
+
+ vec4 sph_near, sph_far;
+ if ((dst_head > dst_tail) && (ProjectionMatrix[3][3] == 0.0)) {
+ sph_near = tailSphere;
+ sph_far = headSphere;
+ }
+ else {
+ sph_near = headSphere;
+ sph_far = tailSphere;
+ }
+
+ vec3 bone_vec = (sph_far.xyz - sph_near.xyz) + 1e-8;
+
+ Bone b;
+ float bone_lenrcp = 1.0 / max(1e-8, sqrt(dot(bone_vec, bone_vec)));
+ b.sinb = (sph_far.w - sph_near.w) * bone_lenrcp * sph_near.w;
+ b.vec = bone_vec * bone_lenrcp;
+
+ float z_ofs_near, z_ofs_far;
+ mat3 mat_near = compute_mat(sph_near, bone_vec, z_ofs_near);
+ mat3 mat_far = compute_mat(sph_far, bone_vec, z_ofs_far);
+
+ vec3 wpos0 = get_outline_point(
+ pos0, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);
+ vec3 wpos1 = get_outline_point(
+ pos1, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);
+ vec3 wpos2 = get_outline_point(
+ pos2, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);
+
+ vec4 pos_4d = vec4(wpos1, 1.0);
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(pos_4d.xyz);
+#endif
+
+ vec4 V = ViewMatrix * pos_4d;
+ float pres_fac = (ProjectionMatrix[3][3] == 0.0) ? abs(V.z) : 1.0;
+
+ vec4 p0 = ViewProjectionMatrix * vec4(wpos0, 1.0);
+ vec4 p1 = ProjectionMatrix * V;
+ vec4 p2 = ViewProjectionMatrix * vec4(wpos2, 1.0);
+
+ /* compute position from 3 vertex because the change in direction
+ * can happen very quicky and lead to very thin edges. */
+ vec2 ss0 = proj(p0);
+ vec2 ss1 = proj(p1);
+ vec2 ss2 = proj(p2);
+ vec2 edge_dir = compute_dir(ss0, ss1, ss2);
+
+ float line_thickness = 2.0 * sizePixel;
+ bool outer = ((gl_VertexID & 1) == 1);
+ vec2 t = outlineColorSize.w * line_thickness * sizeViewportInv.xy;
+ t *= pres_fac;
+ t = (outer) ? t : vec2(0.0);
+
+ gl_Position = p1;
+ gl_Position.xy += t * edge_dir;
+
+ finalColor = vec4(outlineColorSize.rgb, 1.0);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl
new file mode 100644
index 00000000000..d0a8e48657e
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl
@@ -0,0 +1,25 @@
+
+uniform float alpha = 0.6;
+uniform bool isDistance;
+
+flat in vec3 finalStateColor;
+flat in vec3 finalBoneColor;
+in vec3 normalView;
+
+out vec4 fragColor;
+
+void main()
+{
+ float n = normalize(normalView).z;
+ if (isDistance) {
+ n = 1.0 - clamp(-n, 0.0, 1.0);
+ fragColor = vec4(1.0, 1.0, 1.0, 0.2) * n;
+ }
+ else {
+ /* Smooth lighting factor. */
+ const float s = 0.2; /* [0.0-0.5] range */
+ float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0);
+ fragColor.rgb = mix(finalStateColor, finalBoneColor, fac);
+ fragColor.a = alpha;
+ }
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl
new file mode 100644
index 00000000000..620b3f2527c
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl
@@ -0,0 +1,55 @@
+
+/* ---- Instantiated Attrs ---- */
+in vec3 pos;
+
+/* ---- Per instance Attrs ---- */
+/* Assumed to be in world coordinate already. */
+in vec4 headSphere;
+in vec4 tailSphere;
+in vec3 xAxis;
+in vec3 stateColor;
+in vec3 boneColor;
+
+flat out vec3 finalStateColor;
+flat out vec3 finalBoneColor;
+out vec3 normalView;
+
+void main()
+{
+ vec3 bone_vec = tailSphere.xyz - headSphere.xyz;
+ float bone_len = max(1e-8, sqrt(dot(bone_vec, bone_vec)));
+ float bone_lenrcp = 1.0 / bone_len;
+#ifdef SMOOTH_ENVELOPE
+ float sinb = (tailSphere.w - headSphere.w) * bone_lenrcp;
+#else
+ const float sinb = 0.0;
+#endif
+
+ vec3 y_axis = bone_vec * bone_lenrcp;
+ vec3 z_axis = normalize(cross(xAxis, -y_axis));
+ vec3 x_axis = cross(y_axis, z_axis); /* cannot trust xAxis to be orthogonal. */
+
+ vec3 sp, nor;
+ nor = sp = pos.xyz;
+
+ /* In bone space */
+ bool is_head = (pos.z < -sinb);
+ sp *= (is_head) ? headSphere.w : tailSphere.w;
+ sp.z += (is_head) ? 0.0 : bone_len;
+
+ /* Convert to world space */
+ mat3 bone_mat = mat3(x_axis, y_axis, z_axis);
+ sp = bone_mat * sp.xzy + headSphere.xyz;
+ nor = bone_mat * nor.xzy;
+
+ normalView = mat3(ViewMatrix) * nor;
+
+ finalStateColor = stateColor;
+ finalBoneColor = boneColor;
+
+ vec4 pos_4d = vec4(sp, 1.0);
+ gl_Position = ViewProjectionMatrix * pos_4d;
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(pos_4d.xyz);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl
new file mode 100644
index 00000000000..bd05c7f3532
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl
@@ -0,0 +1,116 @@
+
+layout(lines_adjacency) in;
+layout(triangle_strip, max_vertices = 6) out;
+
+in vec4 pPos[];
+in vec3 vPos[];
+in vec2 ssPos[];
+in vec2 ssNor[];
+in vec4 vColSize[];
+
+flat out vec4 finalColor;
+
+vec2 compute_dir(vec2 v0, vec2 v1)
+{
+ vec2 dir = normalize(v1 - v0);
+ dir = vec2(-dir.y, dir.x);
+ return dir;
+}
+
+void emit_edge(vec2 edge_dir, vec2 hidden_dir, vec2 thick, bool is_persp)
+{
+ float fac = dot(-hidden_dir, edge_dir);
+ edge_dir *= (fac < 0.0) ? -1.0 : 1.0;
+
+ vec2 t = thick * (is_persp ? abs(vPos[1].z) : 1.0);
+ gl_Position = pPos[1];
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
+#endif
+ EmitVertex();
+ gl_Position.xy += t * edge_dir;
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
+#endif
+ EmitVertex();
+
+ t = thick * (is_persp ? abs(vPos[2].z) : 1.0);
+ gl_Position = pPos[2];
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[2].gl_ClipDistance);
+#endif
+ EmitVertex();
+ gl_Position.xy += t * edge_dir;
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[2].gl_ClipDistance);
+#endif
+ EmitVertex();
+}
+
+void emit_corner(const int e, vec2 thick, bool is_persp)
+{
+ vec2 corner_dir = ssNor[e];
+ vec2 t = thick * (is_persp ? abs(vPos[e].z) : 1.0);
+
+ gl_Position = pPos[e] + vec4(t * corner_dir, 0.0, 0.0);
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[e].gl_ClipDistance);
+#endif
+ EmitVertex();
+}
+
+void main(void)
+{
+ finalColor = vec4(vColSize[0].rgb, 1.0);
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ vec3 view_vec = (is_persp) ? normalize(vPos[1]) : vec3(0.0, 0.0, -1.0);
+ vec3 v10 = vPos[0] - vPos[1];
+ vec3 v12 = vPos[2] - vPos[1];
+ vec3 v13 = vPos[3] - vPos[1];
+
+ vec3 n0 = cross(v12, v10);
+ vec3 n3 = cross(v13, v12);
+
+ float fac0 = dot(view_vec, n0);
+ float fac3 = dot(view_vec, n3);
+
+ /* If one of the face is perpendicular to the view,
+ * consider it and outline edge. */
+ if (abs(fac0) > 1e-5 && abs(fac3) > 1e-5) {
+ /* If both adjacent verts are facing the camera the same way,
+ * then it isn't an outline edge. */
+ if (sign(fac0) == sign(fac3)) {
+ return;
+ }
+ }
+
+ /* Don't outline if concave edge. */
+ if (dot(n0, v13) > 0.0001) {
+ return;
+ }
+
+ float line_thickness = 2.0 * sizePixel;
+ vec2 thick = vColSize[0].w * (line_thickness * sizeViewportInv.xy);
+ vec2 edge_dir = compute_dir(ssPos[1], ssPos[2]);
+
+ vec2 hidden_point;
+ /* Take the farthest point to compute edge direction
+ * (avoid problems with point behind near plane).
+ * If the chosen point is parallel to the edge in screen space,
+ * choose the other point anyway.
+ * This fixes some issue with cubes in orthographic views.*/
+ if (vPos[0].z < vPos[3].z) {
+ hidden_point = (abs(fac0) > 1e-5) ? ssPos[0] : ssPos[3];
+ }
+ else {
+ hidden_point = (abs(fac3) > 1e-5) ? ssPos[3] : ssPos[0];
+ }
+ vec2 hidden_dir = normalize(hidden_point - ssPos[1]);
+
+ emit_corner(1, thick, is_persp);
+ emit_edge(edge_dir, hidden_dir, thick, is_persp);
+ emit_corner(2, thick, is_persp);
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl
new file mode 100644
index 00000000000..cd9368a997a
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl
@@ -0,0 +1,48 @@
+
+/* ---- Instantiated Attrs ---- */
+in vec3 pos;
+in vec3 snor;
+
+/* ---- Per instance Attrs ---- */
+in vec4 color;
+in mat4 inst_obmat;
+
+out vec4 pPos;
+out vec3 vPos;
+out vec2 ssPos;
+out vec2 ssNor;
+out vec4 vColSize;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy;
+}
+
+void main()
+{
+ vec4 bone_color, state_color;
+ mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color);
+
+ vec4 worldPosition = model_mat * vec4(pos, 1.0);
+ vec4 viewpos = ViewMatrix * worldPosition;
+
+ vPos = viewpos.xyz;
+ pPos = ProjectionMatrix * viewpos;
+
+ /* This is slow and run per vertex, but it's still faster than
+ * doing it per instance on CPU and sending it on via instance attribute. */
+ mat3 normal_mat = transpose(inverse(mat3(model_mat)));
+ /* TODO FIX: there is still a problem with this vector
+ * when the bone is scaled or in persp mode. But it's
+ * barelly visible at the outline corners. */
+ ssNor = normalize(normal_world_to_view(normal_mat * snor).xy);
+
+ ssPos = proj(pPos);
+
+ vColSize = bone_color;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(worldPosition.xyz);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl
new file mode 100644
index 00000000000..39963344dd8
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl
@@ -0,0 +1,11 @@
+
+uniform float alpha = 0.6;
+
+in vec4 finalColor;
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(finalColor.rgb, alpha);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl
new file mode 100644
index 00000000000..8284bd43adc
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl
@@ -0,0 +1,37 @@
+
+/* ---- Instantiated Attrs ---- */
+in vec3 pos;
+in vec3 nor;
+
+/* ---- Per instance Attrs ---- */
+in mat4 inst_obmat;
+
+out vec4 finalColor;
+
+void main()
+{
+ vec4 bone_color, state_color;
+ mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color);
+
+ /* This is slow and run per vertex, but it's still faster than
+ * doing it per instance on CPU and sending it on via instance attribute. */
+ mat3 normal_mat = transpose(inverse(mat3(model_mat)));
+ vec3 normal = normalize(normal_world_to_view(normal_mat * nor));
+
+ /* Do lighting at an angle to avoid flat shading on front facing bone. */
+ const vec3 light = vec3(0.1, 0.1, 0.8);
+ float n = dot(normal, light);
+
+ /* Smooth lighting factor. */
+ const float s = 0.2; /* [0.0-0.5] range */
+ float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0);
+ finalColor.rgb = mix(state_color.rgb, bone_color.rgb, fac);
+ finalColor.a = 1.0;
+
+ vec4 worldPosition = model_mat * vec4(pos, 1.0);
+ gl_Position = ViewProjectionMatrix * worldPosition;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(worldPosition.xyz);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl
new file mode 100644
index 00000000000..9dd4c444116
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl
@@ -0,0 +1,104 @@
+
+/* ---- Instantiated Attrs ---- */
+in vec2 pos0;
+in vec2 pos1;
+
+/* ---- Per instance Attrs ---- */
+in mat4 inst_obmat;
+
+flat out vec4 finalColor;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy;
+}
+
+vec2 compute_dir(vec2 v0, vec2 v1, vec2 c)
+{
+ vec2 dir = normalize(v1 - v0);
+ dir = vec2(dir.y, -dir.x);
+ /* The model matrix can be scaled negativly.
+ * Use projected sphere center to determine
+ * the outline direction. */
+ vec2 cv = c - v0;
+ dir = (dot(dir, cv) > 0.0) ? -dir : dir;
+ return dir;
+}
+
+void main()
+{
+ vec4 bone_color, state_color;
+ mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color);
+
+ mat4 model_view_matrix = ViewMatrix * model_mat;
+ mat4 sphereMatrix = inverse(model_view_matrix);
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ /* This is the local space camera ray (not normalize).
+ * In perspective mode it's also the viewspace position
+ * of the sphere center. */
+ vec3 cam_ray = (is_persp) ? model_view_matrix[3].xyz : vec3(0.0, 0.0, -1.0);
+ cam_ray = mat3(sphereMatrix) * cam_ray;
+
+ /* Sphere center distance from the camera (persp) in local space. */
+ float cam_dist = length(cam_ray);
+
+ /* Compute view aligned orthonormal space. */
+ vec3 z_axis = cam_ray / cam_dist;
+ vec3 x_axis = normalize(cross(sphereMatrix[1].xyz, z_axis));
+ vec3 y_axis = cross(z_axis, x_axis);
+ float z_ofs = 0.0;
+
+ if (is_persp) {
+ /* For perspective, the projected sphere radius
+ * can be bigger than the center disc. Compute the
+ * max angular size and compensate by sliding the disc
+ * towards the camera and scale it accordingly. */
+ const float half_pi = 3.1415926 * 0.5;
+ const float rad = 0.05;
+ /* Let be (in local space):
+ * V the view vector origin.
+ * O the sphere origin.
+ * T the point on the target circle.
+ * We compute the angle between (OV) and (OT). */
+ float a = half_pi - asin(rad / cam_dist);
+ float cos_b = cos(a);
+ float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0));
+
+ x_axis *= sin_b;
+ y_axis *= sin_b;
+ z_ofs = -rad * cos_b;
+ }
+
+ /* Camera oriented position (but still in local space) */
+ vec3 cam_pos0 = x_axis * pos0.x + y_axis * pos0.y + z_axis * z_ofs;
+ vec3 cam_pos1 = x_axis * pos1.x + y_axis * pos1.y + z_axis * z_ofs;
+
+ vec4 V = model_view_matrix * vec4(cam_pos0, 1.0);
+ vec4 p0 = ProjectionMatrix * V;
+ vec4 p1 = ProjectionMatrix * (model_view_matrix * vec4(cam_pos1, 1.0));
+ vec4 c = ProjectionMatrix * vec4(model_view_matrix[3].xyz, 1.0);
+
+ vec2 ssc = proj(c);
+ vec2 ss0 = proj(p0);
+ vec2 ss1 = proj(p1);
+ vec2 edge_dir = compute_dir(ss0, ss1, ssc);
+
+ bool outer = ((gl_VertexID & 1) == 1);
+
+ vec2 t = bone_color.w * (2.0 * sizeViewportInv.xy);
+ t *= (is_persp) ? abs(V.z) : 1.0;
+ t = (outer) ? t : vec2(0.0);
+
+ gl_Position = p0;
+ gl_Position.xy += t * edge_dir;
+
+ finalColor = vec4(bone_color.rgb, 1.0);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ vec4 worldPosition = model_mat * vec4(cam_pos0, 1.0);
+ world_clip_planes_calc_clip_distance(worldPosition.xyz);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl
new file mode 100644
index 00000000000..94f339c4561
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl
@@ -0,0 +1,76 @@
+
+uniform float alpha = 0.4;
+
+flat in vec3 finalStateColor;
+flat in vec3 finalBoneColor;
+flat in mat4 sphereMatrix;
+in vec3 viewPosition;
+
+#ifdef GL_ARB_conservative_depth
+/* Saves a lot of overdraw! */
+layout(depth_greater) out float gl_FragDepth;
+#endif
+
+out vec4 fragColor;
+
+#define cameraPos ViewMatrixInverse[3].xyz
+
+float get_depth_from_view_z(float z)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ z = (-ProjectionMatrix[3][2] / z) - ProjectionMatrix[2][2];
+ }
+ else {
+ z = z * ProjectionMatrix[2][2] / (1.0 - ProjectionMatrix[3][2]);
+ }
+ return z * 0.5 + 0.5;
+}
+
+void main()
+{
+ const float sphere_radius = 0.05;
+
+ bool is_perp = (ProjectionMatrix[3][3] == 0.0);
+ vec3 ray_ori_view = (is_perp) ? vec3(0.0) : viewPosition.xyz;
+ vec3 ray_dir_view = (is_perp) ? viewPosition : vec3(0.0, 0.0, -1.0);
+
+ /* Single matrix mul without branch. */
+ vec4 mul_vec = (is_perp) ? vec4(ray_dir_view, 0.0) : vec4(ray_ori_view, 1.0);
+ vec3 mul_res = (sphereMatrix * mul_vec).xyz;
+
+ /* Reminder :
+ * sphereMatrix[3] is the view space origin in sphere space (sph_ori -> view_ori).
+ * sphereMatrix[2] is the view space Z axis in sphere space. */
+
+ /* convert to sphere local space */
+ vec3 ray_ori = (is_perp) ? sphereMatrix[3].xyz : mul_res;
+ vec3 ray_dir = (is_perp) ? mul_res : -sphereMatrix[2].xyz;
+ float ray_len = length(ray_dir);
+ ray_dir /= ray_len;
+
+ /* Line to sphere intersect */
+ const float sphere_radius_sqr = sphere_radius * sphere_radius;
+ float b = dot(ray_ori, ray_dir);
+ float c = dot(ray_ori, ray_ori) - sphere_radius_sqr;
+ float h = b * b - c;
+ float t = -sqrt(max(0.0, h)) - b;
+
+ /* Compute dot product for lighting */
+ vec3 p = ray_dir * t + ray_ori; /* Point on sphere */
+ vec3 n = normalize(p); /* Normal is just the point in sphere space, normalized. */
+ vec3 l = normalize(sphereMatrix[2].xyz); /* Just the view Z axis in the sphere space. */
+
+ /* Smooth lighting factor. */
+ const float s = 0.2; /* [0.0-0.5] range */
+ float fac = clamp((dot(n, l) * (1.0 - s)) + s, 0.0, 1.0);
+ fragColor.rgb = mix(finalStateColor, finalBoneColor, fac);
+
+ /* 2x2 dither pattern to smooth the lighting. */
+ float dither = (0.5 + dot(vec2(ivec2(gl_FragCoord.xy) & ivec2(1)), vec2(1.0, 2.0))) * 0.25;
+ dither *= (1.0 / 255.0); /* Assume 8bit per color buffer. */
+
+ fragColor = vec4(fragColor.rgb + dither, alpha);
+
+ t /= ray_len;
+ gl_FragDepth = get_depth_from_view_z(ray_dir_view.z * t + ray_ori_view.z);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl
new file mode 100644
index 00000000000..e6fa29ce851
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl
@@ -0,0 +1,87 @@
+
+/* ---- Instantiated Attrs ---- */
+in vec2 pos;
+
+/* ---- Per instance Attrs ---- */
+in vec4 color;
+in mat4 inst_obmat;
+
+flat out vec3 finalStateColor;
+flat out vec3 finalBoneColor;
+flat out mat4 sphereMatrix;
+out vec3 viewPosition;
+
+/* Sphere radius */
+const float rad = 0.05;
+
+void main()
+{
+ vec4 bone_color, state_color;
+ mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color);
+
+ mat4 model_view_matrix = ViewMatrix * model_mat;
+ sphereMatrix = inverse(model_view_matrix);
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ /* This is the local space camera ray (not normalize).
+ * In perspective mode it's also the viewspace position
+ * of the sphere center. */
+ vec3 cam_ray = (is_persp) ? model_view_matrix[3].xyz : vec3(0.0, 0.0, -1.0);
+ cam_ray = mat3(sphereMatrix) * cam_ray;
+
+ /* Sphere center distance from the camera (persp) in local space. */
+ float cam_dist = length(cam_ray);
+
+ /* Compute view aligned orthonormal space. */
+ vec3 z_axis = cam_ray / cam_dist;
+ vec3 x_axis = normalize(cross(sphereMatrix[1].xyz, z_axis));
+ vec3 y_axis = cross(z_axis, x_axis);
+
+ float z_ofs = -rad - 1e-8; /* offset to the front of the sphere */
+ if (is_persp) {
+ /* For perspective, the projected sphere radius
+ * can be bigger than the center disc. Compute the
+ * max angular size and compensate by sliding the disc
+ * towards the camera and scale it accordingly. */
+ const float half_pi = 3.1415926 * 0.5;
+ /* Let be (in local space):
+ * V the view vector origin.
+ * O the sphere origin.
+ * T the point on the target circle.
+ * We compute the angle between (OV) and (OT). */
+ float a = half_pi - asin(rad / cam_dist);
+ float cos_b = cos(a);
+ float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0));
+#if 1
+ /* Instead of choosing the biggest circle in screenspace,
+ * we choose the nearest with the same angular size. This
+ * permit us to leverage GL_ARB_conservative_depth in the
+ * fragment shader. */
+ float minor = cam_dist - rad;
+ float major = cam_dist - cos_b * rad;
+ float fac = minor / major;
+ sin_b *= fac;
+#else
+ z_ofs = -rad * cos_b;
+#endif
+ x_axis *= sin_b;
+ y_axis *= sin_b;
+ }
+
+ /* Camera oriented position (but still in local space) */
+ vec3 cam_pos = x_axis * pos.x + y_axis * pos.y + z_axis * z_ofs;
+
+ vec4 pos_4d = vec4(cam_pos, 1.0);
+ vec4 V = model_view_matrix * pos_4d;
+ gl_Position = ProjectionMatrix * V;
+ viewPosition = V.xyz;
+
+ finalStateColor = state_color.xyz;
+ finalBoneColor = bone_color.xyz;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ vec4 worldPosition = model_mat * pos_4d;
+ world_clip_planes_calc_clip_distance(worldPosition.xyz);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl
new file mode 100644
index 00000000000..ba89619e051
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl
@@ -0,0 +1,13 @@
+
+noperspective in float colorFac;
+flat in vec4 finalWireColor;
+flat in vec4 finalInnerColor;
+
+out vec4 fragColor;
+
+void main()
+{
+ float fac = smoothstep(1.0, 0.2, colorFac);
+ fragColor.rgb = mix(finalInnerColor.rgb, finalWireColor.rgb, fac);
+ fragColor.a = 1.0;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl
new file mode 100644
index 00000000000..99bdbfea2be
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl
@@ -0,0 +1,90 @@
+
+/* ---- Instantiated Attrs ---- */
+in vec2 pos; /* bone aligned screen space */
+in uint flag;
+
+#define COL_WIRE 1u /* (1 << 0) */
+#define COL_HEAD 2u /* (1 << 1) */
+#define COL_TAIL 4u /* (1 << 2) */
+#define COL_BONE 8u /* (1 << 3) */
+
+#define POS_HEAD 16u /* (1 << 4) */
+#define POS_TAIL 32u /* (1 << 5) */ /* UNUSED */
+#define POS_BONE 64u /* (1 << 6) */
+
+/* ---- Per instance Attrs ---- */
+in vec3 boneStart;
+in vec3 boneEnd;
+in vec4 wireColor; /* alpha encode if we do wire. If 0.0 we dont. */
+in vec4 boneColor; /* alpha encode if we do bone. If 0.0 we dont. */
+in vec4 headColor; /* alpha encode if we do head. If 0.0 we dont. */
+in vec4 tailColor; /* alpha encode if we do tail. If 0.0 we dont. */
+
+#define do_wire (wireColor.a > 0.0)
+#define is_head bool(flag & POS_HEAD)
+#define is_bone bool(flag & POS_BONE)
+
+noperspective out float colorFac;
+flat out vec4 finalWireColor;
+flat out vec4 finalInnerColor;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy;
+}
+
+void main()
+{
+ finalInnerColor = ((flag & COL_HEAD) != 0u) ? headColor : tailColor;
+ finalInnerColor = ((flag & COL_BONE) != 0u) ? boneColor : finalInnerColor;
+ finalWireColor = (do_wire) ? wireColor : finalInnerColor;
+ /* Make the color */
+ colorFac = ((flag & COL_WIRE) == 0u) ? ((flag & COL_BONE) != 0u) ? 1.0 : 2.0 : 0.0;
+
+ vec4 boneStart_4d = vec4(boneStart, 1.0);
+ vec4 boneEnd_4d = vec4(boneEnd, 1.0);
+ vec4 v0 = ViewMatrix * boneStart_4d;
+ vec4 v1 = ViewMatrix * boneEnd_4d;
+
+ /* Clip the bone to the camera origin plane (not the clip plane)
+ * to avoid glitches if one end is behind the camera origin (in persp). */
+ float clip_dist = (ProjectionMatrix[3][3] == 0.0) ?
+ -1e-7 :
+ 1e20; /* hardcoded, -1e-8 is giving gliches. */
+ vec3 bvec = v1.xyz - v0.xyz;
+ vec3 clip_pt = v0.xyz + bvec * ((v0.z - clip_dist) / -bvec.z);
+ if (v0.z > clip_dist) {
+ v0.xyz = clip_pt;
+ }
+ else if (v1.z > clip_dist) {
+ v1.xyz = clip_pt;
+ }
+
+ vec4 p0 = ProjectionMatrix * v0;
+ vec4 p1 = ProjectionMatrix * v1;
+
+ float h = (is_head) ? p0.w : p1.w;
+
+ vec2 x_screen_vec = normalize(proj(p1) - proj(p0) + 1e-8);
+ vec2 y_screen_vec = vec2(x_screen_vec.y, -x_screen_vec.x);
+
+ /* 2D screen aligned pos at the point */
+ vec2 vpos = pos.x * x_screen_vec + pos.y * y_screen_vec;
+ vpos *= (ProjectionMatrix[3][3] == 0.0) ? h : 1.0;
+ vpos *= (do_wire) ? 1.0 : 0.5;
+
+ if (finalInnerColor.a > 0.0) {
+ float stick_size = sizePixel * 5.0;
+ gl_Position = (is_head) ? p0 : p1;
+ gl_Position.xy += stick_size * (vpos * sizeViewportInv.xy);
+ gl_Position.z += (is_bone) ? 0.0 : 1e-6; /* Avoid Z fighting of head/tails. */
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance((is_head ? boneStart_4d : boneEnd_4d).xyz);
+#endif
+ }
+ else {
+ gl_Position = vec4(0.0);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl
new file mode 100644
index 00000000000..4e207b96016
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl
@@ -0,0 +1,18 @@
+
+in vec3 color;
+in vec3 pos;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ finalColor.rgb = color;
+ finalColor.a = 1.0;
+
+ vec3 worldPosition = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(worldPosition);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(worldPosition);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl b/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl
new file mode 100644
index 00000000000..7a3af0f3b61
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl
@@ -0,0 +1,14 @@
+
+in vec3 pos;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl
new file mode 100644
index 00000000000..b6576ba7a21
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl
@@ -0,0 +1,114 @@
+
+/* Keep the same value of `ACTIVE_NURB` in `draw_cache_imp_curve.c` */
+#define ACTIVE_NURB 1 << 2
+#define EVEN_U_BIT 1 << 3
+
+layout(lines) in;
+layout(triangle_strip, max_vertices = 10) out;
+
+uniform bool showCurveHandles;
+
+flat in int vertFlag[];
+
+out vec4 finalColor;
+
+void output_line(vec2 offset, vec4 color)
+{
+ finalColor = color;
+
+ gl_Position = gl_in[0].gl_Position;
+ gl_Position.xy += offset * gl_in[0].gl_Position.w;
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[0].gl_ClipDistance);
+#endif
+ EmitVertex();
+
+ gl_Position = gl_in[1].gl_Position;
+ gl_Position.xy += offset * gl_in[1].gl_Position.w;
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
+#endif
+ EmitVertex();
+}
+
+void main()
+{
+ vec4 v1 = gl_in[0].gl_Position;
+ vec4 v2 = gl_in[1].gl_Position;
+
+ int is_active_nurb = (vertFlag[1] & ACTIVE_NURB);
+ int color_id = (vertFlag[1] >> 4);
+
+ /* Don't output any edges if we don't show handles */
+ if (!showCurveHandles && (color_id < 5)) {
+ return;
+ }
+
+ bool edge_selected = (((vertFlag[1] | vertFlag[0]) & VERT_SELECTED) != 0);
+
+ vec4 inner_color;
+ if (color_id == 0) {
+ inner_color = (edge_selected) ? colorHandleSelFree : colorHandleFree;
+ }
+ else if (color_id == 1) {
+ inner_color = (edge_selected) ? colorHandleSelAuto : colorHandleAuto;
+ }
+ else if (color_id == 2) {
+ inner_color = (edge_selected) ? colorHandleSelVect : colorHandleVect;
+ }
+ else if (color_id == 3) {
+ inner_color = (edge_selected) ? colorHandleSelAlign : colorHandleAlign;
+ }
+ else if (color_id == 4) {
+ inner_color = (edge_selected) ? colorHandleSelAutoclamp : colorHandleAutoclamp;
+ }
+ else {
+ bool is_selected = (((vertFlag[1] & vertFlag[0]) & VERT_SELECTED) != 0);
+ bool is_u_segment = (((vertFlag[1] ^ vertFlag[0]) & EVEN_U_BIT) != 0);
+ if (is_u_segment) {
+ inner_color = (is_selected) ? colorNurbSelUline : colorNurbUline;
+ }
+ else {
+ inner_color = (is_selected) ? colorNurbSelVline : colorNurbVline;
+ }
+ }
+
+ vec4 outer_color = (is_active_nurb != 0) ?
+ mix(colorActiveSpline,
+ inner_color,
+ 0.25) /* Minimize active color bleeding on inner_color. */
+ :
+ vec4(inner_color.rgb, 0.0);
+
+ vec2 v1_2 = (v2.xy / v2.w - v1.xy / v1.w);
+ vec2 offset = sizeEdge * 4.0 * sizeViewportInv.xy; /* 4.0 is eyeballed */
+
+ if (abs(v1_2.x * sizeViewport.x) < abs(v1_2.y * sizeViewport.y)) {
+ offset.y = 0.0;
+ }
+ else {
+ offset.x = 0.0;
+ }
+
+ /* draw the transparent border (AA). */
+ if (is_active_nurb != 0) {
+ offset *= 0.75; /* Don't make the active "halo" appear very thick. */
+ output_line(offset * 2.0, vec4(colorActiveSpline.rgb, 0.0));
+ }
+
+ /* draw the outline. */
+ output_line(offset, outer_color);
+
+ /* draw the core of the line. */
+ output_line(vec2(0.0), inner_color);
+
+ /* draw the outline. */
+ output_line(-offset, outer_color);
+
+ /* draw the transparent border (AA). */
+ if (is_active_nurb != 0) {
+ output_line(offset * -2.0, vec4(colorActiveSpline.rgb, 0.0));
+ }
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl
new file mode 100644
index 00000000000..a2b0d072719
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl
@@ -0,0 +1,18 @@
+
+in vec3 pos;
+in int data;
+
+flat out int vertFlag;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+ vertFlag = data;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl
new file mode 100644
index 00000000000..aca40bba171
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl
@@ -0,0 +1,29 @@
+
+in vec3 pos;
+in int data;
+
+out vec4 finalColor;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ if ((data & VERT_SELECTED) != 0) {
+ if ((data & VERT_ACTIVE) != 0) {
+ finalColor = colorEditMeshActive;
+ }
+ else {
+ finalColor = colorVertexSelect;
+ }
+ }
+ else {
+ finalColor = colorVertex;
+ }
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+ gl_PointSize = sizeVertex * 2.0;
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl
new file mode 100644
index 00000000000..5dd8e579db3
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl
@@ -0,0 +1,31 @@
+
+uniform float normalSize;
+
+in vec3 pos;
+in vec3 nor;
+in vec3 tan;
+in float rad;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 final_pos = pos;
+
+ float flip = (gl_InstanceID != 0) ? -1.0 : 1.0;
+
+ if (gl_VertexID % 2 == 0) {
+ final_pos += normalSize * rad * (flip * nor - tan);
+ }
+
+ vec3 world_pos = point_object_to_world(final_pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ finalColor = colorWireEdit;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl
new file mode 100644
index 00000000000..06d34c22ba1
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl
@@ -0,0 +1,32 @@
+
+in vec3 pos;
+in int data;
+
+out vec4 finalColor;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ if ((data & VERT_SELECTED) != 0) {
+ finalColor = colorVertexSelect;
+ }
+ else if ((data & VERT_ACTIVE) != 0) {
+ finalColor = colorEditMeshActive;
+ }
+ else {
+ finalColor = colorVertex;
+ }
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ /* Small offset in Z */
+ gl_Position.z -= 3e-4;
+
+ gl_PointSize = sizeVertex * 2.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl
new file mode 100644
index 00000000000..efa6ca72feb
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl
@@ -0,0 +1,38 @@
+
+uniform sampler1D weightTex;
+
+in vec3 pos;
+in float weight;
+
+out vec4 finalColor;
+
+#define no_active_weight 666.0
+
+vec3 weight_to_rgb(float t)
+{
+ if (t == no_active_weight) {
+ /* No weight. */
+ return colorWire.rgb;
+ }
+ if (t > 1.0 || t < 0.0) {
+ /* Error color */
+ return vec3(1.0, 0.0, 1.0);
+ }
+ else {
+ return texture(weightTex, t).rgb;
+ }
+}
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ finalColor = vec4(weight_to_rgb(weight), 1.0);
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl
new file mode 100644
index 00000000000..8d96c0e418f
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl
@@ -0,0 +1,8 @@
+out vec4 fragColor;
+
+in vec4 weightColor;
+
+void main()
+{
+ fragColor = weightColor;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl
new file mode 100644
index 00000000000..b89a3f407f9
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl
@@ -0,0 +1,35 @@
+
+in vec3 pos;
+in float weight;
+
+uniform sampler1D weightTex;
+
+out vec4 weightColor;
+
+vec3 weight_to_rgb(float t)
+{
+ if (t < 0.0) {
+ /* Minimum color, grey */
+ return vec3(0.25, 0.25, 0.25);
+ }
+ else if (t > 1.0) {
+ /* Error color */
+ return vec3(1.0, 0.0, 1.0);
+ }
+ else {
+ return texture(weightTex, t).rgb;
+ }
+}
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+ weightColor = vec4(weight_to_rgb(weight), 1.0);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
new file mode 100644
index 00000000000..b79bae45f23
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
@@ -0,0 +1,76 @@
+
+uniform bool selectFaces = true;
+uniform bool selectEdges = true;
+
+vec4 EDIT_MESH_edge_color_outer(int edge_flag, int face_flag, float crease, float bweight)
+{
+ vec4 color = vec4(0.0);
+ color = ((edge_flag & EDGE_FREESTYLE) != 0) ? colorEdgeFreestyle : color;
+ color = ((edge_flag & EDGE_SHARP) != 0) ? colorEdgeSharp : color;
+ color = (crease > 0.0) ? vec4(colorEdgeCrease.rgb, crease) : color;
+ color = (bweight > 0.0) ? vec4(colorEdgeBWeight.rgb, bweight) : color;
+ color = ((edge_flag & EDGE_SEAM) != 0) ? colorEdgeSeam : color;
+ return color;
+}
+
+vec4 EDIT_MESH_edge_color_inner(int edge_flag)
+{
+ vec4 color = colorWireEdit;
+ vec4 color_select = (selectEdges) ? colorEdgeSelect : mix(colorEdgeSelect, colorWireEdit, .45);
+ color = ((edge_flag & EDGE_SELECTED) != 0) ? color_select : color;
+ color = ((edge_flag & EDGE_ACTIVE) != 0) ? colorEditMeshActive : color;
+
+ color.a = (selectEdges || (edge_flag & (EDGE_SELECTED | EDGE_ACTIVE)) != 0) ? 1.0 : 0.4;
+ return color;
+}
+
+vec4 EDIT_MESH_edge_vertex_color(int vertex_flag)
+{
+ vec4 color = colorWireEdit;
+ vec4 color_select = (selectEdges) ? colorEdgeSelect : mix(colorEdgeSelect, colorWireEdit, .45);
+
+ bool edge_selected = (vertex_flag & (VERT_ACTIVE | VERT_SELECTED)) != 0;
+ color = (edge_selected) ? color_select : color;
+
+ color.a = (selectEdges || edge_selected) ? 1.0 : 0.4;
+ return color;
+}
+
+vec4 EDIT_MESH_vertex_color(int vertex_flag)
+{
+ if ((vertex_flag & VERT_ACTIVE) != 0) {
+ return vec4(colorEditMeshActive.xyz, 1.0);
+ }
+ else if ((vertex_flag & VERT_SELECTED) != 0) {
+ return colorVertexSelect;
+ }
+ else {
+ return colorVertex;
+ }
+}
+
+vec4 EDIT_MESH_face_color(int face_flag)
+{
+ vec4 color = colorFace;
+ vec4 color_active = mix(colorFaceSelect, colorEditMeshActive, 0.5);
+ color = ((face_flag & FACE_FREESTYLE) != 0) ? colorFaceFreestyle : color;
+ color = ((face_flag & FACE_SELECTED) != 0) ? colorFaceSelect : color;
+ color = ((face_flag & FACE_ACTIVE) != 0) ? color_active : color;
+ color.a *= ((face_flag & (FACE_FREESTYLE | FACE_SELECTED | FACE_ACTIVE)) == 0 || selectFaces) ?
+ 1.0 :
+ 0.5;
+ return color;
+}
+
+vec4 EDIT_MESH_facedot_color(float facedot_flag)
+{
+ if (facedot_flag < 0.0f) {
+ return vec4(colorEditMeshActive.xyz, 1.0);
+ }
+ else if (facedot_flag > 0.0f) {
+ return colorFaceDot;
+ }
+ else {
+ return colorVertex;
+ }
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_frag.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_frag.glsl
new file mode 100644
index 00000000000..a8371958ec2
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_frag.glsl
@@ -0,0 +1,7 @@
+flat in vec4 faceColor;
+out vec4 FragColor;
+
+void main()
+{
+ FragColor = faceColor;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_vert.glsl
new file mode 100644
index 00000000000..df37c6fb0bc
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_vert.glsl
@@ -0,0 +1,23 @@
+
+uniform ivec4 dataMask = ivec4(0xFF);
+
+in vec3 pos;
+in ivec4 data;
+
+flat out vec4 faceColor;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ ivec4 data_m = data & dataMask;
+
+ faceColor = EDIT_MESH_face_color(data_m.x);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl
new file mode 100644
index 00000000000..1fe20d1cb1f
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl
@@ -0,0 +1,46 @@
+
+#define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */
+
+/**
+ * We want to know how much a pixel is covered by a line.
+ * We replace the square pixel with acircle of the same area and try to find the intersection area.
+ * The area we search is the circular segment. https://en.wikipedia.org/wiki/Circular_segment
+ * The formula for the area uses inverse trig function and is quite complexe. Instead,
+ * we approximate it by using the smoothstep function and a 1.05 factor to the disc radius.
+ */
+#define DISC_RADIUS (M_1_SQRTPI * 1.05)
+#define GRID_LINE_SMOOTH_START (0.5 - DISC_RADIUS)
+#define GRID_LINE_SMOOTH_END (0.5 + DISC_RADIUS)
+
+uniform sampler2D depthTex;
+uniform float alpha = 1.0;
+
+flat in vec4 finalColorOuter_f;
+in vec4 finalColor_f;
+noperspective in float edgeCoord_f;
+
+out vec4 FragColor;
+
+bool test_occlusion()
+{
+ return gl_FragCoord.z > texelFetch(depthTex, ivec2(gl_FragCoord.xy), 0).r;
+}
+
+void main()
+{
+ float dist = abs(edgeCoord_f) - max(sizeEdge - 0.5, 0.0);
+ float dist_outer = dist - max(sizeEdge, 1.0);
+#ifdef USE_SMOOTH_WIRE
+ float mix_w = smoothstep(GRID_LINE_SMOOTH_START, GRID_LINE_SMOOTH_END, dist);
+ float mix_w_outer = smoothstep(GRID_LINE_SMOOTH_START, GRID_LINE_SMOOTH_END, dist_outer);
+#else
+ float mix_w = step(0.5, dist);
+ float mix_w_outer = step(0.5, dist_outer);
+#endif
+ /* Line color & alpha. */
+ FragColor = mix(finalColorOuter_f, finalColor_f, 1.0 - mix_w * finalColorOuter_f.a);
+ /* Line edges shape. */
+ FragColor.a *= 1.0 - (finalColorOuter_f.a > 0.0 ? mix_w_outer : mix_w);
+
+ FragColor.a *= test_occlusion() ? alpha : 1.0;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl
new file mode 100644
index 00000000000..92252bbd223
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl
@@ -0,0 +1,88 @@
+
+layout(lines) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+in vec4 finalColor[2];
+in vec4 finalColorOuter[2];
+in int selectOveride[2];
+
+flat out vec4 finalColorOuter_f;
+out vec4 finalColor_f;
+noperspective out float edgeCoord_f;
+
+void do_vertex(vec4 color, vec4 pos, float coord, vec2 offset)
+{
+ finalColor_f = color;
+ edgeCoord_f = coord;
+ gl_Position = pos;
+ /* Multiply offset by 2 because gl_Position range is [-1..1]. */
+ gl_Position.xy += offset * 2.0 * pos.w;
+ /* Correct but fails due to an AMD compiler bug, see: T62792.
+ * Do inline instead. */
+#if 0
+ world_clip_planes_set_clip_distance(gl_in[i].gl_ClipDistance);
+#endif
+ EmitVertex();
+}
+
+void main()
+{
+ vec2 ss_pos[2];
+
+ /* Clip line against near plane to avoid deformed lines. */
+ vec4 pos0 = gl_in[0].gl_Position;
+ vec4 pos1 = gl_in[1].gl_Position;
+ vec2 pz_ndc = vec2(pos0.z / pos0.w, pos1.z / pos1.w);
+ bvec2 clipped = lessThan(pz_ndc, vec2(-1.0));
+ if (all(clipped)) {
+ /* Totally clipped. */
+ return;
+ }
+
+ vec4 pos01 = pos0 - pos1;
+ float ofs = abs((pz_ndc.y + 1.0) / (pz_ndc.x - pz_ndc.y));
+ if (clipped.y) {
+ pos1 += pos01 * ofs;
+ }
+ else if (clipped.x) {
+ pos0 -= pos01 * (1.0 - ofs);
+ }
+
+ ss_pos[0] = pos0.xy / pos0.w;
+ ss_pos[1] = pos1.xy / pos1.w;
+
+ vec2 line = ss_pos[0] - ss_pos[1];
+ line = abs(line) * sizeViewport.xy;
+
+ finalColorOuter_f = finalColorOuter[0];
+ float half_size = sizeEdge;
+ /* Enlarge edge for flag display. */
+ half_size += (finalColorOuter_f.a > 0.0) ? max(sizeEdge, 1.0) : 0.0;
+
+#ifdef USE_SMOOTH_WIRE
+ /* Add 1 px for AA */
+ half_size += 0.5;
+#endif
+
+ vec3 edge_ofs = vec3(half_size * sizeViewportInv.xy, 0.0);
+
+ bool horizontal = line.x > line.y;
+ edge_ofs = (horizontal) ? edge_ofs.zyz : edge_ofs.xzz;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ /* Due to an AMD glitch, this line was moved out of the `do_vertex`
+ * function (see T62792). */
+ world_clip_planes_set_clip_distance(gl_in[0].gl_ClipDistance);
+#endif
+ do_vertex(finalColor[0], pos0, half_size, edge_ofs.xy);
+ do_vertex(finalColor[0], pos0, -half_size, -edge_ofs.xy);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
+#endif
+ vec4 final_color = (selectOveride[0] == 0) ? finalColor[1] : finalColor[0];
+ do_vertex(final_color, pos1, half_size, edge_ofs.xy);
+ do_vertex(final_color, pos1, -half_size, -edge_ofs.xy);
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl
new file mode 100644
index 00000000000..2a00160836b
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl
@@ -0,0 +1,53 @@
+
+uniform float normalSize;
+uniform sampler2D depthTex;
+uniform float alpha = 1.0;
+
+in vec3 pos;
+in vec3 lnor;
+in vec3 vnor;
+in vec4 norAndFlag;
+
+flat out vec4 finalColor;
+
+bool test_occlusion()
+{
+ vec3 ndc = (gl_Position.xyz / gl_Position.w) * 0.5 + 0.5;
+ return (ndc.z - 0.00035) > texture(depthTex, ndc.xy).r;
+}
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 nor;
+ /* Select the right normal by cheking if the generic attrib is used. */
+ if (!all(equal(lnor, vec3(0)))) {
+ nor = lnor;
+ finalColor = colorLNormal;
+ }
+ else if (!all(equal(vnor, vec3(0)))) {
+ nor = vnor;
+ finalColor = colorVNormal;
+ }
+ else {
+ nor = norAndFlag.xyz;
+ finalColor = colorNormal;
+ }
+
+ vec3 n = normalize(normal_object_to_world(nor));
+
+ vec3 world_pos = point_object_to_world(pos);
+
+ if (gl_VertexID == 0) {
+ world_pos += n * normalSize;
+ }
+
+ gl_Position = point_world_to_ndc(world_pos);
+
+ finalColor.a *= (test_occlusion()) ? alpha : 1.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl
new file mode 100644
index 00000000000..944eb41058e
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl
@@ -0,0 +1,25 @@
+
+/* ---- Instantiated Attrs ---- */
+in vec3 pos;
+
+/* ---- Per instance Attrs ---- */
+in float size;
+in vec3 local_pos;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ mat3 imat = mat3(ModelMatrixInverse);
+ vec3 right = normalize(imat * screenVecs[0].xyz);
+ vec3 up = normalize(imat * screenVecs[1].xyz);
+ vec3 screen_pos = (right * pos.x + up * pos.z) * size;
+ vec4 pos_4d = ModelMatrix * vec4(local_pos + screen_pos, 1.0);
+ gl_Position = ViewProjectionMatrix * pos_4d;
+ /* Manual stipple: one segment out of 2 is transparent. */
+ finalColor = ((gl_VertexID & 1) == 0) ? colorSkinRoot : vec4(0.0);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(pos_4d.xyz);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
new file mode 100644
index 00000000000..8759ef80888
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
@@ -0,0 +1,97 @@
+
+uniform sampler2D depthTex;
+uniform float alpha = 1.0;
+uniform ivec4 dataMask = ivec4(0xFF);
+
+in ivec4 data;
+in vec3 pos;
+#ifndef FACEDOT
+in vec3 vnor;
+#else
+in vec4 norAndFlag;
+# define vnor norAndFlag.xyz
+#endif
+
+out vec4 finalColor;
+#ifdef EDGE
+out vec4 finalColorOuter;
+#endif
+#ifdef USE_GEOM_SHADER
+out int selectOveride;
+#endif
+
+bool test_occlusion()
+{
+ vec3 ndc = (gl_Position.xyz / gl_Position.w) * 0.5 + 0.5;
+ return ndc.z > texture(depthTex, ndc.xy).r;
+}
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ ivec4 m_data = data & dataMask;
+
+#if defined(VERT)
+ finalColor = EDIT_MESH_vertex_color(m_data.y);
+ gl_PointSize = sizeVertex * 2.0;
+ /* Make selected and active vertex always on top. */
+ if ((data.x & VERT_SELECTED) != 0) {
+ gl_Position.z -= 1e-7;
+ }
+ if ((data.x & VERT_ACTIVE) != 0) {
+ gl_Position.z -= 1e-7;
+ }
+
+ bool occluded = test_occlusion();
+
+#elif defined(EDGE)
+# ifdef FLAT
+ finalColor = EDIT_MESH_edge_color_inner(m_data.y);
+ selectOveride = 1;
+# else
+ finalColor = EDIT_MESH_edge_vertex_color(m_data.y);
+ selectOveride = (m_data.y & EDGE_SELECTED);
+# endif
+
+ float crease = float(m_data.z) / 255.0;
+ float bweight = float(m_data.w) / 255.0;
+ finalColorOuter = EDIT_MESH_edge_color_outer(m_data.y, m_data.x, crease, bweight);
+
+ bool occluded = false; /* Done in fragment shader */
+
+#elif defined(FACE)
+ finalColor = EDIT_MESH_face_color(m_data.x);
+ bool occluded = true;
+
+#elif defined(FACEDOT)
+ finalColor = EDIT_MESH_facedot_color(norAndFlag.w);
+
+ /* Bias Facedot Z position in clipspace. */
+ gl_Position.z -= 0.00035;
+ gl_PointSize = sizeFaceDot;
+
+ bool occluded = test_occlusion();
+
+#endif
+
+ finalColor.a *= (occluded) ? alpha : 1.0;
+
+#if !defined(FACE)
+ /* Facing based color blend */
+ vec3 vpos = point_world_to_view(world_pos);
+ vec3 view_normal = normalize(normal_object_to_view(vnor) + 1e-4);
+ vec3 view_vec = (ProjectionMatrix[3][3] == 0.0) ? normalize(vpos) : vec3(0.0, 0.0, 1.0);
+ float facing = dot(view_vec, view_normal);
+ facing = 1.0 - abs(facing) * 0.2;
+
+ finalColor.rgb = mix(colorEditMeshMiddle.rgb, finalColor.rgb, facing);
+#endif
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl
new file mode 100644
index 00000000000..86d5547225c
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl
@@ -0,0 +1,19 @@
+
+in vec3 pos;
+in float color;
+
+out vec4 finalColor;
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ finalColor = mix(colorWire, colorEdgeSelect, color);
+
+ gl_PointSize = sizeVertex * 2.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl
new file mode 100644
index 00000000000..1dde94f751c
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl
@@ -0,0 +1,42 @@
+
+uniform sampler1D weightTex;
+uniform bool useWeight;
+
+in vec3 pos;
+in float color;
+
+out vec4 finalColor;
+
+#define no_active_weight 666.0
+
+vec3 weight_to_rgb(float t)
+{
+ if (t == no_active_weight) {
+ /* No weight. */
+ return colorWire.rgb;
+ }
+ if (t > 1.0 || t < 0.0) {
+ /* Error color */
+ return vec3(1.0, 0.0, 1.0);
+ }
+ else {
+ return texture(weightTex, t).rgb;
+ }
+}
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ if (useWeight) {
+ finalColor = vec4(weight_to_rgb(color), 1.0);
+ }
+ else {
+ finalColor = mix(colorWire, colorEdgeSelect, color);
+ }
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_frag.glsl
new file mode 100644
index 00000000000..8a8ae8a9611
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_frag.glsl
@@ -0,0 +1,13 @@
+
+noperspective in vec2 edgePos;
+flat in vec2 edgeStart;
+flat in vec4 finalColor;
+
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 lineOutput;
+
+void main()
+{
+ fragColor = finalColor;
+ lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos);
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl
new file mode 100644
index 00000000000..4b08ea587d4
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl
@@ -0,0 +1,30 @@
+
+in vec3 pos;
+
+/* Instance */
+in vec3 inst_pos;
+
+flat out vec4 finalColor;
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
+
+void main()
+{
+ finalColor = colorLight;
+
+ /* Relative to DPI scalling. Have constant screen size. */
+ vec3 screen_pos = screenVecs[0].xyz * pos.x + screenVecs[1].xyz * pos.y;
+ vec3 p = inst_pos;
+ p.z *= (pos.z == 0.0) ? 0.0 : 1.0;
+ float screen_size = mul_project_m4_v3_zfac(p) * sizePixel;
+ vec3 world_pos = p + screen_pos * screen_size;
+
+ gl_Position = point_world_to_ndc(world_pos);
+
+ /* Convert to screen position [0..sizeVp]. */
+ edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl
new file mode 100644
index 00000000000..8784b6cd73a
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl
@@ -0,0 +1,18 @@
+
+in vec4 finalColor;
+
+out vec4 fragColor;
+
+void main()
+{
+ vec2 centered = abs(gl_PointCoord - vec2(0.5));
+ float dist = max(centered.x, centered.y);
+
+ float fac = dist * dist * 4.0;
+ fragColor = mix(colorEditMeshMiddle, finalColor, 0.45 + fac * 0.65);
+
+ /* Make the effect more like a fresnel by offsetting
+ * the depth and creating mini-spheres.
+ * Disabled as it has performance impact. */
+ // gl_FragDepth = gl_FragCoord.z + 1e-6 * fac;
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl
new file mode 100644
index 00000000000..76a2678a50e
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl
@@ -0,0 +1,20 @@
+
+in vec3 pos;
+
+out vec4 finalColor;
+
+void main()
+{
+ /* Extract data packed inside the unused mat4 members. */
+ mat4 obmat = ModelMatrix;
+ finalColor = vec4(obmat[0][3], obmat[1][3], obmat[2][3], obmat[3][3]);
+
+ vec3 world_pos = (ModelMatrix * vec4(pos, 1.0)).xyz;
+ gl_Position = point_world_to_ndc(world_pos);
+
+ gl_PointSize = sizeVertex * 2.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl
new file mode 100644
index 00000000000..14c03248981
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl
@@ -0,0 +1,30 @@
+
+uniform vec4 color;
+
+in vec3 pos;
+
+out vec4 radii;
+out vec4 fillColor;
+out vec4 outlineColor;
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ gl_PointSize = sizeObjectCenter;
+ float radius = 0.5 * sizeObjectCenter;
+ float outline_width = sizePixel;
+ radii[0] = radius;
+ radii[1] = radius - 1.0;
+ radii[2] = radius - outline_width;
+ radii[3] = radius - outline_width - 1.0;
+ radii /= sizeObjectCenter;
+
+ fillColor = color;
+ outlineColor = colorOutline;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl
new file mode 100644
index 00000000000..a72c5adb691
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl
@@ -0,0 +1,227 @@
+
+in vec3 pos;
+in int vclass;
+
+/* Instance */
+in mat4 inst_obmat;
+in vec4 color;
+
+#define lamp_area_size inst_data.xy
+#define lamp_clip_sta inst_data.z
+#define lamp_clip_end inst_data.w
+
+#define lamp_spot_cosine inst_data.x
+#define lamp_spot_blend inst_data.y
+
+#define camera_corner inst_data.xy
+#define camera_center inst_data.zw
+#define camera_dist inst_color_data
+#define camera_dist_sta inst_data.z
+#define camera_dist_end inst_data.w
+#define camera_distance_color inst_data.x
+
+#define empty_size inst_data.xyz
+#define empty_scale inst_data.w
+
+#define VCLASS_LIGHT_AREA_SHAPE (1 << 0)
+#define VCLASS_LIGHT_SPOT_SHAPE (1 << 1)
+#define VCLASS_LIGHT_SPOT_BLEND (1 << 2)
+#define VCLASS_LIGHT_SPOT_CONE (1 << 3)
+#define VCLASS_LIGHT_DIST (1 << 4)
+
+#define VCLASS_CAMERA_FRAME (1 << 5)
+#define VCLASS_CAMERA_DIST (1 << 6)
+#define VCLASS_CAMERA_VOLUME (1 << 7)
+
+#define VCLASS_SCREENSPACE (1 << 8)
+#define VCLASS_SCREENALIGNED (1 << 9)
+
+#define VCLASS_EMPTY_SCALED (1 << 10)
+#define VCLASS_EMPTY_AXES (1 << 11)
+#define VCLASS_EMPTY_AXES_NAME (1 << 12)
+#define VCLASS_EMPTY_AXES_SHADOW (1 << 13)
+#define VCLASS_EMPTY_SIZE (1 << 14)
+
+flat out vec4 finalColor;
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
+
+void main()
+{
+ /* Extract data packed inside the unused mat4 members. */
+ vec4 inst_data = vec4(inst_obmat[0][3], inst_obmat[1][3], inst_obmat[2][3], inst_obmat[3][3]);
+ float inst_color_data = color.a;
+ mat4 obmat = inst_obmat;
+ obmat[0][3] = obmat[1][3] = obmat[2][3] = 0.0;
+ obmat[3][3] = 1.0;
+
+ finalColor = color;
+ if (color.a < 0.0) {
+ finalColor.a = 1.0;
+ }
+
+ float lamp_spot_sine;
+ vec3 vpos = pos;
+ vec3 vofs = vec3(0.0);
+ /* Lights */
+ if ((vclass & VCLASS_LIGHT_AREA_SHAPE) != 0) {
+ /* HACK: use alpha color for spots to pass the area_size. */
+ if (inst_color_data < 0.0) {
+ lamp_area_size.xy = vec2(-inst_color_data);
+ }
+ vpos.xy *= lamp_area_size.xy;
+ }
+ else if ((vclass & VCLASS_LIGHT_SPOT_SHAPE) != 0) {
+ lamp_spot_sine = sqrt(1.0 - lamp_spot_cosine * lamp_spot_cosine);
+ lamp_spot_sine *= ((vclass & VCLASS_LIGHT_SPOT_BLEND) != 0) ? lamp_spot_blend : 1.0;
+ vpos = vec3(pos.xy * lamp_spot_sine, -lamp_spot_cosine);
+ }
+ else if ((vclass & VCLASS_LIGHT_DIST) != 0) {
+ /* Meh nasty mess. Select one of the 6 axes to display on. (see light_distance_z_get()) */
+ int dist_axis = int(pos.z);
+ float dist = pos.z - floor(pos.z) - 0.5;
+ float inv = sign(dist);
+ dist = (abs(dist) > 0.15) ? lamp_clip_end : lamp_clip_sta;
+ vofs[dist_axis] = inv * dist / length(obmat[dist_axis].xyz);
+ vpos.z = 0.0;
+ if (lamp_clip_end < 0.0) {
+ vpos = vofs = vec3(0.0);
+ }
+ }
+ /* Camera */
+ else if ((vclass & VCLASS_CAMERA_FRAME) != 0) {
+ if ((vclass & VCLASS_CAMERA_VOLUME) != 0) {
+ vpos.z = mix(color.b, color.a, pos.z);
+ }
+ else if (camera_dist > 0.0) {
+ vpos.z = -abs(camera_dist);
+ }
+ else {
+ vpos.z *= -abs(camera_dist);
+ }
+ vpos.xy = (camera_center + camera_corner * vpos.xy) * abs(vpos.z);
+ }
+ else if ((vclass & VCLASS_CAMERA_DIST) != 0) {
+ vofs.xy = vec2(0.0);
+ vofs.z = -mix(camera_dist_sta, camera_dist_end, pos.z);
+ vpos.z = 0.0;
+ /* Distance line endpoints color */
+ if (any(notEqual(pos.xy, vec2(0.0)))) {
+ /* Override color. */
+ switch (int(camera_distance_color)) {
+ case 0: /* Mist */
+ finalColor = vec4(0.5, 0.5, 0.5, 1.0);
+ break;
+ case 1: /* Mist Active */
+ finalColor = vec4(1.0, 1.0, 1.0, 1.0);
+ break;
+ case 2: /* Clip */
+ finalColor = vec4(0.5, 0.5, 0.25, 1.0);
+ break;
+ case 3: /* Clip Active */
+ finalColor = vec4(1.0, 1.0, 0.5, 1.0);
+ break;
+ }
+ }
+ /* Focus cross */
+ if (pos.z == 2.0) {
+ vofs.z = 0.0;
+ if (camera_dist < 0.0) {
+ vpos.z = -abs(camera_dist);
+ }
+ else {
+ /* Disabled */
+ vpos = vec3(0.0);
+ }
+ }
+ }
+ /* Empties */
+ else if ((vclass & VCLASS_EMPTY_SCALED) != 0) {
+ /* This is a bit silly but we avoid scalling the object matrix on CPU (saving a mat4 mul) */
+ vpos *= empty_scale;
+ }
+ else if ((vclass & VCLASS_EMPTY_SIZE) != 0) {
+ /* This is a bit silly but we avoid scalling the object matrix on CPU (saving a mat4 mul) */
+ vpos *= empty_size;
+ }
+ else if ((vclass & VCLASS_EMPTY_AXES) != 0) {
+ float axis = vpos.z;
+ vofs[int(axis)] = (1.0 + fract(axis)) * empty_scale;
+ /* Scale uniformly by axis length */
+ vpos *= length(obmat[int(axis)].xyz) * empty_scale;
+
+ vec3 axis_color = vec3(0.0);
+ axis_color[int(axis)] = 1.0;
+ finalColor.rgb = mix(axis_color + fract(axis), color.rgb, color.a);
+ finalColor.a = 1.0;
+ }
+
+ /* Not exclusive with previous flags. */
+ if ((vclass & VCLASS_CAMERA_VOLUME) != 0) {
+ /* Unpack final color. */
+ int color_class = int(floor(color.r));
+ float color_intensity = fract(color.r);
+ switch (color_class) {
+ case 0: /* No eye (convergence plane) */
+ finalColor = vec4(1.0, 1.0, 1.0, 1.0);
+ break;
+ case 1: /* Left eye */
+ finalColor = vec4(0.0, 1.0, 1.0, 1.0);
+ break;
+ case 2: /* Right eye */
+ finalColor = vec4(1.0, 0.0, 0.0, 1.0);
+ break;
+ }
+ finalColor *= vec4(vec3(color_intensity), color.g);
+ }
+
+ vec3 world_pos;
+ if ((vclass & VCLASS_SCREENSPACE) != 0) {
+ /* Relative to DPI scalling. Have constant screen size. */
+ vec3 screen_pos = screenVecs[0].xyz * vpos.x + screenVecs[1].xyz * vpos.y;
+ vec3 p = (obmat * vec4(vofs, 1.0)).xyz;
+ float screen_size = mul_project_m4_v3_zfac(p) * sizePixel;
+ world_pos = p + screen_pos * screen_size;
+ }
+ else if ((vclass & VCLASS_SCREENALIGNED) != 0) {
+ /* World sized, camera facing geometry. */
+ vec3 screen_pos = screenVecs[0].xyz * vpos.x + screenVecs[1].xyz * vpos.y;
+ world_pos = (obmat * vec4(vofs, 1.0)).xyz + screen_pos;
+ }
+ else {
+ world_pos = (obmat * vec4(vofs + vpos, 1.0)).xyz;
+ }
+
+ if ((vclass & VCLASS_LIGHT_SPOT_CONE) != 0) {
+ /* Compute point on the cone before and after this one. */
+ vec2 perp = vec2(pos.y, -pos.x);
+ const float incr_angle = 2.0 * 3.1415 / 32.0;
+ const vec2 slope = vec2(cos(incr_angle), sin(incr_angle));
+ vec3 p0 = vec3((pos.xy * slope.x + perp * slope.y) * lamp_spot_sine, -lamp_spot_cosine);
+ vec3 p1 = vec3((pos.xy * slope.x - perp * slope.y) * lamp_spot_sine, -lamp_spot_cosine);
+ p0 = (obmat * vec4(p0, 1.0)).xyz;
+ p1 = (obmat * vec4(p1, 1.0)).xyz;
+ /* Compute normals of each side. */
+ vec3 edge = obmat[3].xyz - world_pos;
+ vec3 n0 = normalize(cross(edge, p0 - world_pos));
+ vec3 n1 = normalize(cross(edge, world_pos - p1));
+ bool persp = (ProjectionMatrix[3][3] == 0.0);
+ vec3 V = (persp) ? normalize(ViewMatrixInverse[3].xyz - world_pos) : ViewMatrixInverse[2].xyz;
+ /* Discard non-silhouete edges. */
+ bool facing0 = dot(n0, V) > 0.0;
+ bool facing1 = dot(n1, V) > 0.0;
+ if (facing0 == facing1) {
+ /* Hide line by making it cover 0 pixels. */
+ world_pos = obmat[3].xyz;
+ }
+ }
+
+ gl_Position = point_world_to_ndc(world_pos);
+
+ /* Convert to screen position [0..sizeVp]. */
+ edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl
new file mode 100644
index 00000000000..7e469aee18d
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl
@@ -0,0 +1,31 @@
+
+noperspective in vec2 stipple_coord;
+flat in vec2 stipple_start;
+flat in vec4 finalColor;
+
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 lineOutput;
+
+void main()
+{
+ fragColor = finalColor;
+
+ /* Stipple */
+ const float dash_width = 6.0;
+ const float dash_factor = 0.5;
+
+ lineOutput = pack_line_data(gl_FragCoord.xy, stipple_start, stipple_coord);
+
+ float dist = distance(stipple_start, stipple_coord);
+
+ if (fragColor.a == 0.0) {
+ /* Disable stippling. */
+ dist = 0.0;
+ }
+
+ fragColor.a = 1.0;
+
+ if (fract(dist / dash_width) > dash_factor) {
+ discard;
+ }
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl
new file mode 100644
index 00000000000..933b9d65a5f
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl
@@ -0,0 +1,40 @@
+
+in vec3 pos;
+in vec4 color;
+in int colorid; /* if equal 0 (i.e: Not specified) use color attrib and stippling. */
+
+noperspective out vec2 stipple_coord;
+flat out vec2 stipple_start;
+flat out vec4 finalColor;
+
+vec2 screen_position(vec4 p)
+{
+ return ((p.xy / p.w) * 0.5 + 0.5) * sizeViewport.xy;
+}
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ stipple_coord = stipple_start = screen_position(gl_Position);
+
+#ifdef OBJECT_WIRE
+ /* Extract data packed inside the unused mat4 members. */
+ finalColor = vec4(ModelMatrix[0][3], ModelMatrix[1][3], ModelMatrix[2][3], ModelMatrix[3][3]);
+#else
+
+ if (colorid == TH_CAMERA_PATH) {
+ finalColor = colorCameraPath;
+ finalColor.a = 0.0; /* No Stipple */
+ }
+ else {
+ finalColor = color;
+ finalColor.a = 1.0; /* Stipple */
+ }
+#endif
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/shaders/facing_frag.glsl b/source/blender/draw/engines/overlay/shaders/facing_frag.glsl
new file mode 100644
index 00000000000..1ed35b4a421
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/facing_frag.glsl
@@ -0,0 +1,9 @@
+uniform vec3 color_towards = vec3(0.0, 0.0, 1.0);
+uniform vec3 color_outwards = vec3(1.0, 0.0, 0.0);
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(gl_FrontFacing ? color_towards : color_outwards, 0.7);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/facing_vert.glsl b/source/blender/draw/engines/overlay/shaders/facing_vert.glsl
new file mode 100644
index 00000000000..2dd84c0a060
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/facing_vert.glsl
@@ -0,0 +1,12 @@
+
+in vec3 pos;
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl
new file mode 100644
index 00000000000..db845c7f1dd
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl
@@ -0,0 +1,248 @@
+
+/* Infinite grid
+ * Author: Clément Foucault */
+
+/* We use the normalized local position to avoid precision
+ * loss during interpolation. */
+in vec3 local_pos;
+
+out vec4 FragColor;
+
+uniform vec3 planeAxes;
+uniform float gridDistance;
+uniform float meshSize;
+uniform float lineKernel = 0.0;
+uniform sampler2D depthBuffer;
+
+#define cameraPos (ViewMatrixInverse[3].xyz)
+
+uniform int gridFlag;
+
+#define STEPS_LEN 8
+uniform float gridSteps[STEPS_LEN] = float[](0.001, 0.01, 0.1, 1.0, 10.0, 100.0, 1000.0, 10000.0);
+
+#define AXIS_X (1 << 0)
+#define AXIS_Y (1 << 1)
+#define AXIS_Z (1 << 2)
+#define GRID (1 << 3)
+#define PLANE_XY (1 << 4)
+#define PLANE_XZ (1 << 5)
+#define PLANE_YZ (1 << 6)
+#define GRID_BACK (1 << 9) /* grid is behind objects */
+
+#define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */
+
+/**
+ * We want to know how much a pixel is covered by a line.
+ * We replace the square pixel with acircle of the same area and try to find the intersection area.
+ * The area we search is the circular segment. https://en.wikipedia.org/wiki/Circular_segment
+ * The formula for the area uses inverse trig function and is quite complexe. Instead,
+ * we approximate it by using the smoothstep function and a 1.05 factor to the disc radius.
+ */
+#define DISC_RADIUS (M_1_SQRTPI * 1.05)
+#define GRID_LINE_SMOOTH_START (0.5 - DISC_RADIUS)
+#define GRID_LINE_SMOOTH_END (0.5 + DISC_RADIUS)
+
+float get_grid(vec2 co, vec2 fwidthCos, float grid_size)
+{
+ float half_size = grid_size / 2.0;
+ /* triangular wave pattern, amplitude is [0, half_size] */
+ vec2 grid_domain = abs(mod(co + half_size, grid_size) - half_size);
+ /* modulate by the absolute rate of change of the coordinates
+ * (make lines have the same width under perspective) */
+ grid_domain /= fwidthCos;
+
+ /* collapse waves */
+ float line_dist = min(grid_domain.x, grid_domain.y);
+
+ return 1.0 - smoothstep(GRID_LINE_SMOOTH_START, GRID_LINE_SMOOTH_END, line_dist - lineKernel);
+}
+
+vec3 get_axes(vec3 co, vec3 fwidthCos, float line_size)
+{
+ vec3 axes_domain = abs(co);
+ /* modulate by the absolute rate of change of the coordinates
+ * (make line have the same width under perspective) */
+ axes_domain /= fwidthCos;
+
+ return 1.0 - smoothstep(GRID_LINE_SMOOTH_START,
+ GRID_LINE_SMOOTH_END,
+ axes_domain - (line_size + lineKernel));
+}
+
+#define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0, 1.0))
+
+void main()
+{
+ vec3 wPos = local_pos * meshSize;
+ vec3 dFdxPos = dFdx(wPos);
+ vec3 dFdyPos = dFdy(wPos);
+ vec3 fwidthPos = abs(dFdxPos) + abs(dFdyPos);
+ wPos += cameraPos * planeAxes;
+
+ float dist, fade;
+ /* if persp */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ vec3 viewvec = cameraPos - wPos;
+ dist = length(viewvec);
+ viewvec /= dist;
+
+ float angle;
+ if ((gridFlag & PLANE_XZ) != 0) {
+ angle = viewvec.y;
+ }
+ else if ((gridFlag & PLANE_YZ) != 0) {
+ angle = viewvec.x;
+ }
+ else {
+ angle = viewvec.z;
+ }
+
+ angle = 1.0 - abs(angle);
+ angle *= angle;
+ fade = 1.0 - angle * angle;
+ fade *= 1.0 - smoothstep(0.0, gridDistance, dist - gridDistance);
+ }
+ else {
+ dist = abs(gl_FragCoord.z * 2.0 - 1.0);
+ fade = 1.0 - smoothstep(0.0, 0.5, dist - 0.5);
+ dist = 1.0; /* avoid branch after */
+
+ if ((gridFlag & PLANE_XY) != 0) {
+ float angle = 1.0 - abs(ViewMatrixInverse[2].z);
+ dist = 1.0 + angle * 2.0;
+ angle *= angle;
+ fade *= 1.0 - angle * angle;
+ }
+ }
+
+ if ((gridFlag & GRID) != 0) {
+ /* Using `max(dot(dFdxPos, screenVecs[0]), dot(dFdyPos, screenVecs[1]))`
+ * would be more accurate, but not really necessary. */
+ float grid_res = dot(dFdxPos, screenVecs[0].xyz);
+
+ /* The gride begins to appear when it comprises 4 pixels */
+ grid_res *= 4;
+
+ /* from biggest to smallest */
+ vec4 scale;
+#if 0
+ int step_id = 0;
+ scale[0] = 0.0;
+ scale[1] = gridSteps[0];
+ while (scale[1] < grid_res && step_id != STEPS_LEN - 1) {
+ scale[0] = scale[1];
+ scale[1] = gridSteps[++step_id];
+ }
+ scale[2] = gridSteps[min(step_id + 1, STEPS_LEN - 1)];
+ scale[3] = gridSteps[min(step_id + 2, STEPS_LEN - 1)];
+#else
+ /* For more efficiency, unroll the loop above. */
+ if (gridSteps[0] > grid_res) {
+ scale = vec4(0.0, gridSteps[0], gridSteps[1], gridSteps[2]);
+ }
+ else if (gridSteps[1] > grid_res) {
+ scale = vec4(gridSteps[0], gridSteps[1], gridSteps[2], gridSteps[3]);
+ }
+ else if (gridSteps[2] > grid_res) {
+ scale = vec4(gridSteps[1], gridSteps[2], gridSteps[3], gridSteps[4]);
+ }
+ else if (gridSteps[3] > grid_res) {
+ scale = vec4(gridSteps[2], gridSteps[3], gridSteps[4], gridSteps[5]);
+ }
+ else if (gridSteps[4] > grid_res) {
+ scale = vec4(gridSteps[3], gridSteps[4], gridSteps[5], gridSteps[6]);
+ }
+ else if (gridSteps[5] > grid_res) {
+ scale = vec4(gridSteps[4], gridSteps[5], gridSteps[6], gridSteps[7]);
+ }
+ else if (gridSteps[6] > grid_res) {
+ scale = vec4(gridSteps[5], gridSteps[6], gridSteps[7], gridSteps[7]);
+ }
+ else {
+ scale = vec4(gridSteps[6], gridSteps[7], gridSteps[7], gridSteps[7]);
+ }
+#endif
+ float blend = 1.0 - linearstep(scale[0], scale[1], grid_res);
+ blend = blend * blend * blend;
+
+ vec2 grid_pos, grid_fwidth;
+ if ((gridFlag & PLANE_XZ) != 0) {
+ grid_pos = wPos.xz;
+ grid_fwidth = fwidthPos.xz;
+ }
+ else if ((gridFlag & PLANE_YZ) != 0) {
+ grid_pos = wPos.yz;
+ grid_fwidth = fwidthPos.yz;
+ }
+ else {
+ grid_pos = wPos.xy;
+ grid_fwidth = fwidthPos.xy;
+ }
+
+ float gridA = get_grid(grid_pos, grid_fwidth, scale[1]);
+ float gridB = get_grid(grid_pos, grid_fwidth, scale[2]);
+ float gridC = get_grid(grid_pos, grid_fwidth, scale[3]);
+
+ FragColor = colorGrid;
+ FragColor.a *= gridA * blend;
+ FragColor = mix(FragColor, mix(colorGrid, colorGridEmphasise, blend), gridB);
+ FragColor = mix(FragColor, colorGridEmphasise, gridC);
+ }
+ else {
+ FragColor = vec4(colorGrid.rgb, 0.0);
+ }
+
+ if ((gridFlag & (AXIS_X | AXIS_Y | AXIS_Z)) != 0) {
+ /* Setup axes 'domains' */
+ vec3 axes_dist, axes_fwidth;
+
+ if ((gridFlag & AXIS_X) != 0) {
+ axes_dist.x = dot(wPos.yz, planeAxes.yz);
+ axes_fwidth.x = dot(fwidthPos.yz, planeAxes.yz);
+ }
+ if ((gridFlag & AXIS_Y) != 0) {
+ axes_dist.y = dot(wPos.xz, planeAxes.xz);
+ axes_fwidth.y = dot(fwidthPos.xz, planeAxes.xz);
+ }
+ if ((gridFlag & AXIS_Z) != 0) {
+ axes_dist.z = dot(wPos.xy, planeAxes.xy);
+ axes_fwidth.z = dot(fwidthPos.xy, planeAxes.xy);
+ }
+
+ /* Computing all axes at once using vec3 */
+ vec3 axes = get_axes(axes_dist, axes_fwidth, 0.1);
+
+ if ((gridFlag & AXIS_X) != 0) {
+ FragColor.a = max(FragColor.a, axes.x);
+ FragColor.rgb = (axes.x < 1e-8) ? FragColor.rgb : colorGridAxisX.rgb;
+ }
+ if ((gridFlag & AXIS_Y) != 0) {
+ FragColor.a = max(FragColor.a, axes.y);
+ FragColor.rgb = (axes.y < 1e-8) ? FragColor.rgb : colorGridAxisY.rgb;
+ }
+ if ((gridFlag & AXIS_Z) != 0) {
+ FragColor.a = max(FragColor.a, axes.z);
+ FragColor.rgb = (axes.z < 1e-8) ? FragColor.rgb : colorGridAxisZ.rgb;
+ }
+ }
+
+ /* Add a small bias so the grid will always
+ * be on top of a mesh with the same depth. */
+ float grid_depth = gl_FragCoord.z - 6e-8 - fwidth(gl_FragCoord.z);
+ float scene_depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
+ if ((gridFlag & GRID_BACK) != 0) {
+ fade *= (scene_depth == 1.0) ? 1.0 : 0.0;
+ }
+ else {
+ /* Manual, non hard, depth test:
+ * Progressively fade the grid below occluders
+ * (avoids popping visuals due to depth buffer precision) */
+ /* Harder settings tend to flicker more,
+ * but have less "see through" appearance. */
+ const float test_hardness = 1e7;
+ fade *= 1.0 - clamp((grid_depth - scene_depth) * test_hardness, 0.0, 1.0);
+ }
+
+ FragColor.a *= fade;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/grid_vert.glsl
new file mode 100644
index 00000000000..496bb011c74
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/grid_vert.glsl
@@ -0,0 +1,52 @@
+
+/* Infinite grid
+ * Clément Foucault */
+
+uniform vec3 planeAxes;
+uniform float meshSize;
+
+uniform int gridFlag;
+
+#define cameraPos (ViewMatrixInverse[3].xyz)
+
+#define PLANE_XY (1 << 4)
+#define PLANE_XZ (1 << 5)
+#define PLANE_YZ (1 << 6)
+#define CLIP_Z_POS (1 << 7)
+#define CLIP_Z_NEG (1 << 8)
+
+in vec3 pos;
+
+out vec3 local_pos;
+
+void main()
+{
+ vec3 vert_pos;
+
+ /* Project camera pos to the needed plane */
+ if ((gridFlag & PLANE_XY) != 0) {
+ vert_pos = vec3(pos.x, pos.y, 0.0);
+ }
+ else if ((gridFlag & PLANE_XZ) != 0) {
+ vert_pos = vec3(pos.x, 0.0, pos.y);
+ }
+ else {
+ vert_pos = vec3(0.0, pos.x, pos.y);
+ }
+
+ local_pos = vert_pos;
+
+ vec3 real_pos = cameraPos * planeAxes + vert_pos * meshSize;
+
+ /* Used for additional Z axis */
+ if ((gridFlag & CLIP_Z_POS) != 0) {
+ real_pos.z = clamp(real_pos.z, 0.0, 1e30);
+ local_pos.z = clamp(local_pos.z, 0.0, 1.0);
+ }
+ if ((gridFlag & CLIP_Z_NEG) != 0) {
+ real_pos.z = clamp(real_pos.z, -1e30, 0.0);
+ local_pos.z = clamp(local_pos.z, -1.0, 0.0);
+ }
+
+ gl_Position = ViewProjectionMatrix * vec4(real_pos, 1.0);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/image_frag.glsl b/source/blender/draw/engines/overlay/shaders/image_frag.glsl
new file mode 100644
index 00000000000..0da7067851d
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/image_frag.glsl
@@ -0,0 +1,34 @@
+
+uniform sampler2D imgTexture;
+uniform bool imgPremultiplied;
+uniform bool imgAlphaBlend;
+uniform bool imgLinear;
+uniform vec4 color;
+
+in vec2 uvs;
+
+out vec4 fragColor;
+
+void main()
+{
+ vec2 uvs_clamped = clamp(uvs, 0.0, 1.0);
+ vec4 tex_color;
+ if (imgLinear) {
+ tex_color = texture_read_as_linearrgb(imgTexture, imgPremultiplied, uvs_clamped);
+ }
+ else {
+ tex_color = texture_read_as_srgb(imgTexture, imgPremultiplied, uvs_clamped);
+ }
+ fragColor = tex_color * color;
+
+ if (!imgAlphaBlend) {
+ /* Arbitrary discard anything below 5% opacity.
+ * Note that this could be exposed to the User. */
+ if (tex_color.a < 0.05) {
+ discard;
+ }
+ else {
+ fragColor.a = 1.0;
+ }
+ }
+}
diff --git a/source/blender/draw/engines/overlay/shaders/image_vert.glsl b/source/blender/draw/engines/overlay/shaders/image_vert.glsl
new file mode 100644
index 00000000000..621e1d8068b
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/image_vert.glsl
@@ -0,0 +1,21 @@
+
+uniform bool depthSet;
+
+in vec3 pos;
+
+out vec2 uvs;
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ if (depthSet) {
+ /* Result in a position at 1.0 (far plane). Small epsilon to avoid precision issue.
+ * This mimics the effect of infinite projection matrix
+ * (see http://www.terathon.com/gdc07_lengyel.pdf). */
+ gl_Position.z = gl_Position.w - 2.4e-7;
+ }
+
+ uvs = pos.xy * 0.5 + 0.5;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl b/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl
new file mode 100644
index 00000000000..95e5b08049e
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl
@@ -0,0 +1,47 @@
+
+layout(lines) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+uniform int lineThickness = 2;
+
+in vec4 finalColor_geom[];
+in vec2 ssPos[];
+
+out vec4 finalColor;
+
+vec2 compute_dir(vec2 v0, vec2 v1)
+{
+ vec2 dir = normalize(v1 - v0 + 1e-8);
+ dir = vec2(-dir.y, dir.x);
+ return dir;
+}
+
+void main(void)
+{
+ vec2 t;
+ vec2 edge_dir = compute_dir(ssPos[0], ssPos[1]) * sizeViewportInv.xy;
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ float line_size = float(lineThickness) * sizePixel;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[0].gl_ClipDistance);
+#endif
+ finalColor = finalColor_geom[0];
+ t = edge_dir * (line_size * (is_persp ? gl_in[0].gl_Position.w : 1.0));
+ gl_Position = gl_in[0].gl_Position + vec4(t, 0.0, 0.0);
+ EmitVertex();
+ gl_Position = gl_in[0].gl_Position - vec4(t, 0.0, 0.0);
+ EmitVertex();
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[1].gl_ClipDistance);
+#endif
+ finalColor = finalColor_geom[1];
+ t = edge_dir * (line_size * (is_persp ? gl_in[1].gl_Position.w : 1.0));
+ gl_Position = gl_in[1].gl_Position + vec4(t, 0.0, 0.0);
+ EmitVertex();
+ gl_Position = gl_in[1].gl_Position - vec4(t, 0.0, 0.0);
+ EmitVertex();
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl b/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl
new file mode 100644
index 00000000000..6d7f673731e
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl
@@ -0,0 +1,96 @@
+
+uniform ivec4 mpathLineSettings;
+uniform bool selected;
+uniform vec3 customColor;
+
+#define frameCurrent mpathLineSettings.x
+#define frameStart mpathLineSettings.y
+#define frameEnd mpathLineSettings.z
+#define cacheStart mpathLineSettings.w
+
+in vec3 pos;
+
+out vec2 ssPos;
+out vec4 finalColor_geom;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy;
+}
+
+#define SET_INTENSITY(A, B, C, min, max) \
+ (((1.0 - (float(C - B) / float(C - A))) * (max - min)) + min)
+
+void main()
+{
+ gl_Position = ViewProjectionMatrix * vec4(pos, 1.0);
+
+ ssPos = proj(gl_Position);
+
+ int frame = gl_VertexID + cacheStart;
+
+ float intensity; /* how faint */
+
+ vec3 blend_base = (abs(frame - frameCurrent) == 1) ?
+ colorCurrentFrame.rgb :
+ colorBackground.rgb; /* "bleed" cframe color to ease color blending */
+ bool use_custom_color = customColor.x >= 0.0;
+ /* TODO: We might want something more consistent with custom color and standard colors. */
+ if (frame < frameCurrent) {
+ if (use_custom_color) {
+ /* Custom color: previous frames color is darker than current frame */
+ finalColor_geom.rgb = customColor * 0.25;
+ }
+ else {
+ /* black - before frameCurrent */
+ if (selected) {
+ intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.25, 0.75);
+ }
+ else {
+ intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.68, 0.92);
+ }
+ finalColor_geom.rgb = mix(colorWire.rgb, blend_base, intensity);
+ }
+ }
+ else if (frame > frameCurrent) {
+ if (use_custom_color) {
+ /* Custom color: next frames color is equal to user selected color */
+ finalColor_geom.rgb = customColor;
+ }
+ else {
+ /* blue - after frameCurrent */
+ if (selected) {
+ intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.25, 0.75);
+ }
+ else {
+ intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.68, 0.92);
+ }
+
+ finalColor_geom.rgb = mix(colorBonePose.rgb, blend_base, intensity);
+ }
+ }
+ else {
+ if (use_custom_color) {
+ /* Custom color: current frame color is slightly darker than user selected color */
+ finalColor_geom.rgb = customColor * 0.5;
+ }
+ else {
+ /* green - on frameCurrent */
+ if (selected) {
+ intensity = 0.5f;
+ }
+ else {
+ intensity = 0.99f;
+ }
+ finalColor_geom.rgb = clamp(
+ mix(colorCurrentFrame.rgb, colorBackground.rgb, intensity) - 0.1, 0.0, 0.1);
+ }
+ }
+
+ finalColor_geom.a = 1.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl
new file mode 100644
index 00000000000..14335eb1b99
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl
@@ -0,0 +1,58 @@
+
+uniform ivec4 mpathPointSettings;
+uniform bool showKeyFrames = true;
+uniform vec3 customColor;
+
+#define pointSize mpathPointSettings.x
+#define frameCurrent mpathPointSettings.y
+#define cacheStart mpathPointSettings.z
+#define stepSize mpathPointSettings.w
+
+in vec3 pos;
+in int flag;
+
+#define MOTIONPATH_VERT_SEL (1 << 0)
+#define MOTIONPATH_VERT_KEY (1 << 1)
+
+out vec4 finalColor;
+
+void main()
+{
+ gl_Position = ViewProjectionMatrix * vec4(pos, 1.0);
+ gl_PointSize = float(pointSize + 2);
+
+ int frame = gl_VertexID + cacheStart;
+ bool use_custom_color = customColor.x >= 0.0;
+ finalColor = (use_custom_color) ? vec4(customColor, 1.0) : vec4(1.0);
+
+ /* Bias to reduce z fighting with the path */
+ gl_Position.z -= 1e-4;
+
+ if (gl_VertexID % stepSize == 0) {
+ gl_PointSize = float(pointSize) + 4;
+ }
+
+ if (showKeyFrames) {
+ if ((flag & MOTIONPATH_VERT_KEY) != 0) {
+ gl_PointSize = float(pointSize + 5);
+ finalColor = colorVertexSelect;
+ /* Bias more to get these on top of regular points */
+ gl_Position.z -= 1e-4;
+ }
+ /* Draw big green dot where the current frame is.
+ * NOTE: this is only done when keyframes are shown, since this adds similar types of clutter
+ */
+ if (frame == frameCurrent) {
+ gl_PointSize = float(pointSize + 8);
+ finalColor = colorCurrentFrame;
+ /* Bias more to get these on top of keyframes */
+ gl_Position.z -= 1e-4;
+ }
+ }
+
+ gl_PointSize *= sizePixel;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
new file mode 100644
index 00000000000..79c970adfe0
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
@@ -0,0 +1,86 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform usampler2D outlineId;
+uniform sampler2D outlineDepth;
+uniform sampler2D sceneDepth;
+
+uniform float alphaOcclu;
+
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+
+#ifdef GPU_ARB_texture_gather
+ vec2 texel_size = 1.0 / vec2(textureSize(outlineId, 0).xy);
+ vec2 uv = ceil(gl_FragCoord.xy) * texel_size;
+
+ /* Samples order is CW starting from top left. */
+ uvec4 tmp1 = textureGather(outlineId, uv - texel_size);
+ uvec4 tmp2 = textureGather(outlineId, uv);
+
+ uint ref_id = tmp1.y;
+ uvec4 id = uvec4(tmp1.xz, tmp2.xz);
+#else
+ uvec4 id;
+ uint ref_id = texelFetch(outlineId, texel, 0).r;
+ id.x = texelFetchOffset(outlineId, texel, 0, ivec2(-1, 0)).r;
+ id.y = texelFetchOffset(outlineId, texel, 0, ivec2(0, -1)).r;
+ id.z = texelFetchOffset(outlineId, texel, 0, ivec2(0, 1)).r;
+ id.w = texelFetchOffset(outlineId, texel, 0, ivec2(1, 0)).r;
+#endif
+
+#ifdef WIRE
+ /* We want only 2px outlines. */
+ /* TODO optimize, don't sample if we don't need to. */
+ id.xy = uvec2(ref_id);
+#endif
+
+ bool outline = any(notEqual(id, uvec4(ref_id)));
+
+ ivec2 depth_texel = texel;
+ /* If texel is an outline but has no valid id ...
+ * replace id and depth texel by a valid one.
+ * This keeps the outline thickness consistent everywhere. */
+ if (ref_id == 0u && outline) {
+ depth_texel = (id.x != 0u) ? texel + ivec2(-1, 0) : depth_texel;
+ depth_texel = (id.y != 0u) ? texel + ivec2(0, -1) : depth_texel;
+ depth_texel = (id.z != 0u) ? texel + ivec2(0, 1) : depth_texel;
+ depth_texel = (id.w != 0u) ? texel + ivec2(1, 0) : depth_texel;
+
+ ref_id = (id.x != 0u) ? id.x : ref_id;
+ ref_id = (id.y != 0u) ? id.y : ref_id;
+ ref_id = (id.z != 0u) ? id.z : ref_id;
+ ref_id = (id.w != 0u) ? id.w : ref_id;
+ }
+
+ float ref_depth = texelFetch(outlineDepth, depth_texel, 0).r;
+ float scene_depth = texelFetch(sceneDepth, depth_texel, 0).r;
+
+ /* Avoid bad cases of zfighting for occlusion only. */
+ const float epsilon = 3.0 / 8388608.0;
+ bool occluded = (ref_depth > scene_depth + epsilon);
+
+ /* WATCH: Keep in sync with outlineId of the prepass. */
+ uint color_id = ref_id >> 14u;
+ if (ref_id == 0u) {
+ FragColor = vec4(0.0);
+ }
+ else if (color_id == 1u) {
+ FragColor = colorSelect;
+ }
+ else if (color_id == 2u) {
+ FragColor = colorDupliSelect;
+ }
+ else if (color_id == 3u) {
+ FragColor = colorActive;
+ }
+ else {
+ FragColor = colorTransform;
+ }
+
+ FragColor.a *= (occluded) ? alphaOcclu : 1.0;
+ FragColor.a = (outline) ? FragColor.a : 0.0;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_expand_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_expand_frag.glsl
new file mode 100644
index 00000000000..cb9fe0e7c36
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/outline_expand_frag.glsl
@@ -0,0 +1,51 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D outlineColor;
+
+uniform float alpha;
+uniform bool doExpand;
+
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+ FragColor = texelFetch(outlineColor, uv, 0).rgba;
+
+ vec4 color[4];
+ color[0] = texelFetchOffset(outlineColor, uv, 0, ivec2(1, 0)).rgba;
+ color[1] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, 1)).rgba;
+ color[2] = texelFetchOffset(outlineColor, uv, 0, ivec2(-1, 0)).rgba;
+ color[3] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, -1)).rgba;
+
+ vec4 values = vec4(color[0].a, color[1].a, color[2].a, color[3].a);
+
+ vec4 tests = step(vec4(1e-6), values); /* (color.a != 0.0) */
+ bvec4 btests = equal(tests, vec4(1.0));
+
+ if (FragColor.a != 0.0) {
+ return;
+ }
+
+#ifdef LARGE_OUTLINE
+ if (!any(btests)) {
+ color[0] = texelFetchOffset(outlineColor, uv, 0, ivec2(2, 0)).rgba;
+ color[1] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, 2)).rgba;
+ color[2] = texelFetchOffset(outlineColor, uv, 0, ivec2(-2, 0)).rgba;
+ color[3] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, -2)).rgba;
+
+ values = vec4(color[0].a, color[1].a, color[2].a, color[3].a);
+
+ tests = step(vec4(1e-6), values); /* (color.a != 0.0) */
+ btests = equal(tests, vec4(1.0));
+ }
+#endif
+
+ FragColor = (btests.x) ? color[0] : FragColor;
+ FragColor = (btests.y) ? color[1] : FragColor;
+ FragColor = (btests.z) ? color[2] : FragColor;
+ FragColor = (btests.w) ? color[3] : FragColor;
+
+ FragColor.a *= (!doExpand) ? 0.0 : 1.0;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_lightprobe_grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/outline_lightprobe_grid_vert.glsl
new file mode 100644
index 00000000000..144024a7d5d
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/outline_lightprobe_grid_vert.glsl
@@ -0,0 +1,31 @@
+
+uniform ivec3 grid_resolution;
+uniform vec3 corner;
+uniform vec3 increment_x;
+uniform vec3 increment_y;
+uniform vec3 increment_z;
+
+flat out int objectId;
+
+void main()
+{
+ vec3 ls_cell_location;
+ /* Keep in sync with update_irradiance_probe */
+ ls_cell_location.z = float(gl_VertexID % grid_resolution.z);
+ ls_cell_location.y = float((gl_VertexID / grid_resolution.z) % grid_resolution.y);
+ ls_cell_location.x = float(gl_VertexID / (grid_resolution.z * grid_resolution.y));
+
+ vec3 ws_cell_location = corner +
+ (increment_x * ls_cell_location.x + increment_y * ls_cell_location.y +
+ increment_z * ls_cell_location.z);
+
+ gl_Position = ViewProjectionMatrix * vec4(ws_cell_location, 1.0);
+ gl_PointSize = 2.0f;
+
+ /* ID 0 is nothing (background) */
+ objectId = resource_handle + 1;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(ws_cell_location);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
new file mode 100644
index 00000000000..5d6c4881b5b
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
@@ -0,0 +1,18 @@
+
+/* Should be 2 bits only [0..3]. */
+uniform int outlineId;
+
+flat in int objectId;
+
+/* using uint because 16bit uint can contain more ids than int. */
+out uint outId;
+
+/* Replace top 2 bits (of the 16bit output) by outlineId.
+ * This leaves 16K different IDs to create outlines between objects.
+ * SHIFT = (32 - (16 - 2)) */
+#define SHIFT 18u
+
+void main()
+{
+ outId = (uint(outlineId) << 14u) | ((uint(objectId) << SHIFT) >> SHIFT);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl
new file mode 100644
index 00000000000..b32913dcd60
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl
@@ -0,0 +1,54 @@
+
+layout(lines_adjacency) in;
+layout(line_strip, max_vertices = 2) out;
+
+in vec3 vPos[];
+in int objectId_g[];
+
+flat out int objectId;
+
+void vert_from_gl_in(int v)
+{
+ gl_Position = gl_in[v].gl_Position;
+ objectId = objectId_g[v];
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[v].gl_ClipDistance);
+#endif
+}
+
+void main()
+{
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ vec3 view_vec = (is_persp) ? normalize(vPos[1]) : vec3(0.0, 0.0, -1.0);
+
+ vec3 v10 = vPos[0] - vPos[1];
+ vec3 v12 = vPos[2] - vPos[1];
+ vec3 v13 = vPos[3] - vPos[1];
+
+ vec3 n0 = cross(v12, v10);
+ vec3 n3 = cross(v13, v12);
+
+ float fac0 = dot(view_vec, n0);
+ float fac3 = dot(view_vec, n3);
+
+ /* If both adjacent verts are facing the camera the same way,
+ * then it isn't an outline edge. */
+ if (sign(fac0) == sign(fac3)) {
+ return;
+ }
+
+ /* Don't outline if concave edge. */
+ /* That would hide a lot of non useful edge but it flickers badly.
+ * TODO revisit later... */
+ // if (dot(n0, v13) > 0.01)
+ // return;
+
+ vert_from_gl_in(1);
+ EmitVertex();
+
+ vert_from_gl_in(2);
+ EmitVertex();
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
new file mode 100644
index 00000000000..7740f9a4af2
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
@@ -0,0 +1,29 @@
+
+in vec3 pos;
+
+#ifdef USE_GEOM
+out vec3 vPos;
+out int objectId_g;
+# define objectId objectId_g
+#else
+
+flat out int objectId;
+#endif
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+#ifdef USE_GEOM
+ vPos = point_world_to_view(world_pos);
+#endif
+ gl_Position = point_world_to_ndc(world_pos);
+ /* Small bias to always be on top of the geom. */
+ gl_Position.z -= 1e-3;
+
+ /* ID 0 is nothing (background) */
+ objectId = resource_handle + 1;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_resolve_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_resolve_frag.glsl
new file mode 100644
index 00000000000..ba5d073a9c2
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/outline_resolve_frag.glsl
@@ -0,0 +1,21 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D outlineBluredColor;
+uniform vec2 rcpDimensions;
+
+void main()
+{
+#ifdef USE_FXAA
+ float aa_alpha =
+ FxaaPixelShader(uvcoordsvar.st, outlineBluredColor, rcpDimensions, 1.0, 0.166, 0.0833).r;
+#endif
+
+ FragColor = texture(outlineBluredColor, uvcoordsvar.st).rgba;
+
+#ifdef USE_FXAA
+ FragColor.a = aa_alpha;
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl
new file mode 100644
index 00000000000..2b5d586bdd1
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl
@@ -0,0 +1,24 @@
+
+in vec3 pos;
+in vec4 nor; /* select flag on the 4th component */
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ bool is_select = (nor.w > 0.0);
+ bool is_hidden = (nor.w < 0.0);
+
+ /* Don't draw faces that are selected. */
+ if (is_hidden || is_select) {
+ gl_Position = vec4(-2.0, -2.0, -2.0, 1.0);
+ }
+ else {
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+ }
+}
diff --git a/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl
new file mode 100644
index 00000000000..9d102bd4295
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl
@@ -0,0 +1,32 @@
+
+in vec3 pos;
+in vec4 nor; /* select flag on the 4th component */
+
+out vec4 finalColor;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ bool is_select = (nor.w > 0.0);
+ bool is_hidden = (nor.w < 0.0);
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+ /* Add offset in Z to avoid zfighting and render selected wires on top. */
+ /* TODO scale this bias using znear and zfar range. */
+ gl_Position.z -= (is_select ? 2e-4 : 1e-4);
+
+ if (is_hidden) {
+ gl_Position = vec4(-2.0, -2.0, -2.0, 1.0);
+ }
+
+ finalColor = (is_select) ? vec4(1.0) : colorWire;
+ finalColor.a = nor.w;
+
+ gl_PointSize = sizeVertex * 2.0;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl b/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl
new file mode 100644
index 00000000000..4d0692039a4
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl
@@ -0,0 +1,23 @@
+in vec2 uv_interp;
+
+out vec4 fragColor;
+
+uniform float opacity = 1.0;
+
+uniform sampler2D maskImage;
+uniform bool maskImagePremultiplied;
+uniform vec3 maskColor;
+uniform bool maskInvertStencil;
+
+void main()
+{
+ vec4 mask = vec4(texture_read_as_srgb(maskImage, maskImagePremultiplied, uv_interp).rgb, 1.0);
+ if (maskInvertStencil) {
+ mask.rgb = 1.0 - mask.rgb;
+ }
+ float mask_step = smoothstep(0, 3.0, mask.r + mask.g + mask.b);
+ mask.rgb *= maskColor;
+ mask.a = mask_step * opacity;
+
+ fragColor = mask;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl
new file mode 100644
index 00000000000..cb29fefb7ef
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl
@@ -0,0 +1,19 @@
+
+in vec3 pos;
+in vec2 mu; /* masking uv map */
+
+out vec2 uv_interp;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ uv_interp = mu;
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl b/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl
new file mode 100644
index 00000000000..2500ff83abe
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl
@@ -0,0 +1,28 @@
+
+in vec3 finalColor;
+
+out vec4 fragColor;
+
+uniform float opacity = 1.0;
+uniform bool useAlphaBlend = false;
+
+vec3 linear_to_srgb_attr(vec3 c)
+{
+ c = max(c, vec3(0.0));
+ vec3 c1 = c * 12.92;
+ vec3 c2 = 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055;
+ return mix(c1, c2, step(vec3(0.0031308), c));
+}
+
+void main()
+{
+ vec3 color = linear_to_srgb_attr(finalColor);
+
+ if (useAlphaBlend) {
+ fragColor = vec4(color, opacity);
+ }
+ else {
+ /* mix with 1.0 -> is like opacity when using multiply blend mode */
+ fragColor = vec4(mix(vec3(1.0), color, opacity), 1.0);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl
new file mode 100644
index 00000000000..e060e33deba
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl
@@ -0,0 +1,27 @@
+
+in vec3 pos;
+in vec3 ac; /* active color */
+
+out vec3 finalColor;
+
+vec3 srgb_to_linear_attr(vec3 c)
+{
+ c = max(c, vec3(0.0));
+ vec3 c1 = c * (1.0 / 12.92);
+ vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
+ return mix(c1, c2, step(vec3(0.04045), c));
+}
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ finalColor = srgb_to_linear_attr(ac);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl b/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl
new file mode 100644
index 00000000000..0020d76ed6a
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl
@@ -0,0 +1,106 @@
+
+in vec2 weight_interp; /* (weight, alert) */
+
+out vec4 fragColor;
+
+uniform float opacity = 1.0;
+uniform sampler1D colorramp;
+
+uniform bool useAlphaBlend = false;
+uniform bool drawContours = false;
+
+float contours(float value, float steps, float width_px, float max_rel_width, float gradient)
+{
+ /* Minimum visible and minimum full strength line width in screen space for fade out. */
+ const float min_width_px = 1.3, fade_width_px = 2.3;
+ /* Line is thinner towards the increase in the weight gradient by this factor. */
+ const float hi_bias = 2.0;
+
+ /* Don't draw lines at 0 or 1. */
+ float rel_value = value * steps;
+
+ if (rel_value < 0.5 || rel_value > steps - 0.5) {
+ return 0.0;
+ }
+
+ /* Check if completely invisible due to fade out. */
+ float rel_gradient = gradient * steps;
+ float rel_min_width = min_width_px * rel_gradient;
+
+ if (max_rel_width <= rel_min_width) {
+ return 0.0;
+ }
+
+ /* Main shape of the line, accounting for width bias and maximum weight space width. */
+ float rel_width = width_px * rel_gradient;
+
+ float offset = fract(rel_value + 0.5) - 0.5;
+
+ float base_alpha = 1.0 - max(offset * hi_bias, -offset) / min(max_rel_width, rel_width);
+
+ /* Line fadeout when too thin in screen space. */
+ float rel_fade_width = fade_width_px * rel_gradient;
+
+ float fade_alpha = (max_rel_width - rel_min_width) / (rel_fade_width - rel_min_width);
+
+ return clamp(base_alpha, 0.0, 1.0) * clamp(fade_alpha, 0.0, 1.0);
+}
+
+vec4 contour_grid(float weight, float weight_gradient)
+{
+ /* Fade away when the gradient is too low to avoid big fills and noise. */
+ float flt_eps = max(1e-8, 1e-6 * weight);
+
+ if (weight_gradient <= flt_eps) {
+ return vec4(0.0);
+ }
+
+ /* Three levels of grid lines */
+ float grid10 = contours(weight, 10.0, 5.0, 0.3, weight_gradient);
+ float grid100 = contours(weight, 100.0, 3.5, 0.35, weight_gradient) * 0.6;
+ float grid1000 = contours(weight, 1000.0, 2.5, 0.4, weight_gradient) * 0.25;
+
+ /* White lines for 0.1 and 0.01, and black for 0.001 */
+ vec4 grid = vec4(1.0) * max(grid10, grid100);
+
+ grid.a = max(grid.a, grid1000);
+
+ return grid * clamp((weight_gradient - flt_eps) / flt_eps, 0.0, 1.0);
+}
+
+void main()
+{
+ float alert = weight_interp.y;
+ vec4 color;
+
+ /* Missing vertex group alert color. Uniform in practice. */
+ if (alert > 1.1) {
+ color = colorVertexMissingData;
+ }
+ /* Weights are available */
+ else {
+ float weight = weight_interp.x;
+ vec4 weight_color = texture(colorramp, weight, 0);
+
+ /* Contour display */
+ if (drawContours) {
+ /* This must be executed uniformly for all fragments */
+ float weight_gradient = length(vec2(dFdx(weight), dFdy(weight)));
+
+ vec4 grid = contour_grid(weight, weight_gradient);
+
+ weight_color = grid + weight_color * (1 - grid.a);
+ }
+
+ /* Zero weight alert color. Nonlinear blend to reduce impact. */
+ color = mix(weight_color, colorVertexUnreferenced, alert * alert);
+ }
+
+ if (useAlphaBlend) {
+ fragColor = vec4(color.rgb, opacity);
+ }
+ else {
+ /* mix with 1.0 -> is like opacity when using multiply blend mode */
+ fragColor = vec4(mix(vec3(1.0), color.rgb, opacity), 1.0);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl
new file mode 100644
index 00000000000..b3baa8c7b07
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl
@@ -0,0 +1,20 @@
+
+in float weight;
+in vec3 pos;
+
+out vec2 weight_interp; /* (weight, alert) */
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ /* Separate actual weight and alerts for independent interpolation */
+ weight_interp = max(vec2(weight, -weight), 0.0);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl
new file mode 100644
index 00000000000..d5a42d2d309
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl
@@ -0,0 +1,38 @@
+
+uniform bool useSelect;
+
+in vec3 pos;
+in vec4 nor; /* flag stored in w */
+
+flat out vec4 finalColor;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ bool is_select = (nor.w > 0.0) && useSelect;
+ bool is_hidden = (nor.w < 0.0) && useSelect;
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+ /* Add offset in Z to avoid zfighting and render selected wires on top. */
+ /* TODO scale this bias using znear and zfar range. */
+ gl_Position.z -= (is_select ? 2e-4 : 1e-4);
+
+ if (is_hidden) {
+ gl_Position = vec4(-2.0, -2.0, -2.0, 1.0);
+ }
+
+ const vec4 colSel = vec4(1.0);
+
+ finalColor = (is_select) ? colSel : colorWire;
+
+ /* Weight paint needs a light color to contrasts with dark weights. */
+ if (!useSelect) {
+ finalColor = vec4(1.0, 1.0, 1.0, 0.3);
+ }
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/particle_frag.glsl b/source/blender/draw/engines/overlay/shaders/particle_frag.glsl
new file mode 100644
index 00000000000..36928d0c776
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/particle_frag.glsl
@@ -0,0 +1,16 @@
+
+in vec4 finalColor;
+
+out vec4 fragColor;
+
+void main()
+{
+ float dist = length(gl_PointCoord - vec2(0.5));
+
+ if (dist > 0.5) {
+ discard;
+ }
+ /* Nice sphere falloff. */
+ float intensity = sqrt(1.0 - dist * 2.0) * 0.5 + 0.5;
+ fragColor = finalColor * vec4(intensity, intensity, intensity, 1.0);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/particle_vert.glsl b/source/blender/draw/engines/overlay/shaders/particle_vert.glsl
new file mode 100644
index 00000000000..9ff2c42921d
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/particle_vert.glsl
@@ -0,0 +1,68 @@
+
+uniform sampler1D weightTex;
+uniform vec4 color; /* Drawsize packed in alpha */
+
+/* ---- Instantiated Attrs ---- */
+in vec3 pos;
+in int vclass;
+
+/* ---- Per instance Attrs ---- */
+in vec3 part_pos;
+in vec4 part_rot;
+in float part_val;
+
+#ifdef USE_DOTS
+out vec4 finalColor;
+#else
+flat out vec4 finalColor;
+#endif
+
+#define VCLASS_SCREENALIGNED (1 << 9)
+
+#define VCLASS_EMPTY_AXES (1 << 11)
+
+vec3 rotate(vec3 vec, vec4 quat)
+{
+ /* The quaternion representation here stores the w component in the first index */
+ return vec + 2.0 * cross(quat.yzw, cross(quat.yzw, vec) + quat.x * vec);
+}
+
+void main()
+{
+ float draw_size = color.a;
+
+ vec3 world_pos = part_pos;
+
+#ifdef USE_DOTS
+ gl_Position = point_world_to_ndc(world_pos);
+ /* World sized points. */
+ gl_PointSize = sizePixel * draw_size * ProjectionMatrix[1][1] * sizeViewport.y / gl_Position.w;
+#else
+
+ if ((vclass & VCLASS_SCREENALIGNED) != 0) {
+ /* World sized, camera facing geometry. */
+ world_pos += (screenVecs[0].xyz * pos.x + screenVecs[1].xyz * pos.y) * draw_size;
+ }
+ else {
+ world_pos += rotate(pos, part_rot) * draw_size;
+ }
+
+ gl_Position = point_world_to_ndc(world_pos);
+#endif
+
+ /* Coloring */
+ if ((vclass & VCLASS_EMPTY_AXES) != 0) {
+ /* see VBO construction for explanation. */
+ finalColor = vec4(clamp(pos * 10000.0, 0.0, 1.0), 1.0);
+ }
+ else if (part_val < 0.0) {
+ finalColor = vec4(color.rgb, 1.0);
+ }
+ else {
+ finalColor = vec4(texture(weightTex, part_val).rgb, 1.0);
+ }
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl b/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl
new file mode 100644
index 00000000000..18a096da61b
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl
@@ -0,0 +1,20 @@
+
+uniform float maskOpacity;
+
+in vec3 pos;
+in float msk;
+
+out vec4 finalColor;
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ float mask = 1.0 - (msk * maskOpacity);
+ finalColor = vec4(0.0, 0.0, 0.0, mask);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl b/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl
new file mode 100644
index 00000000000..64f88bd74fa
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl
@@ -0,0 +1,117 @@
+
+uniform sampler3D velocityX;
+uniform sampler3D velocityY;
+uniform sampler3D velocityZ;
+uniform float displaySize = 1.0;
+uniform float slicePosition;
+uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
+
+/* SmokeDomainSettings.cell_size */
+uniform vec3 cellSize;
+/* SmokeDomainSettings.p0 */
+uniform vec3 domainOriginOffset;
+/* SmokeDomainSettings.res_min */
+uniform ivec3 adaptiveCellOffset;
+
+flat out vec4 finalColor;
+
+const vec3 corners[4] = vec3[4](vec3(0.0, 0.2, -0.5),
+ vec3(-0.2 * 0.866, -0.2 * 0.5, -0.5),
+ vec3(0.2 * 0.866, -0.2 * 0.5, -0.5),
+ vec3(0.0, 0.0, 0.5));
+
+const int indices[12] = int[12](0, 1, 1, 2, 2, 0, 0, 3, 1, 3, 2, 3);
+
+/* Straight Port from BKE_defvert_weight_to_rgb()
+ * TODO port this to a color ramp. */
+vec3 weight_to_color(float weight)
+{
+ vec3 r_rgb = vec3(0.0);
+ float blend = ((weight / 2.0) + 0.5);
+
+ if (weight <= 0.25) { /* blue->cyan */
+ r_rgb.g = blend * weight * 4.0;
+ r_rgb.b = blend;
+ }
+ else if (weight <= 0.50) { /* cyan->green */
+ r_rgb.g = blend;
+ r_rgb.b = blend * (1.0 - ((weight - 0.25) * 4.0));
+ }
+ else if (weight <= 0.75) { /* green->yellow */
+ r_rgb.r = blend * ((weight - 0.50) * 4.0);
+ r_rgb.g = blend;
+ }
+ else if (weight <= 1.0) { /* yellow->red */
+ r_rgb.r = blend;
+ r_rgb.g = blend * (1.0 - ((weight - 0.75) * 4.0));
+ }
+ else {
+ /* exceptional value, unclamped or nan,
+ * avoid uninitialized memory use */
+ r_rgb = vec3(1.0, 0.0, 1.0);
+ }
+
+ return r_rgb;
+}
+
+mat3 rotation_from_vector(vec3 v)
+{
+ /* Add epsilon to avoid NaN. */
+ vec3 N = normalize(v + 1e-8);
+ vec3 UpVector = abs(N.z) < 0.99999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
+ vec3 T = normalize(cross(UpVector, N));
+ vec3 B = cross(N, T);
+ return mat3(T, B, N);
+}
+
+void main()
+{
+#ifdef USE_NEEDLE
+ int cell = gl_VertexID / 12;
+#else
+ int cell = gl_VertexID / 2;
+#endif
+
+ ivec3 volume_size = textureSize(velocityX, 0);
+
+ ivec3 cell_ofs = ivec3(0);
+ ivec3 cell_div = volume_size;
+ if (sliceAxis == 0) {
+ cell_ofs.x = int(slicePosition * float(volume_size.x));
+ cell_div.x = 1;
+ }
+ else if (sliceAxis == 1) {
+ cell_ofs.y = int(slicePosition * float(volume_size.y));
+ cell_div.y = 1;
+ }
+ else if (sliceAxis == 2) {
+ cell_ofs.z = int(slicePosition * float(volume_size.z));
+ cell_div.z = 1;
+ }
+
+ ivec3 cell_co;
+ cell_co.x = cell % cell_div.x;
+ cell_co.y = (cell / cell_div.x) % cell_div.y;
+ cell_co.z = cell / (cell_div.x * cell_div.y);
+ cell_co += cell_ofs;
+
+ vec3 pos = domainOriginOffset + cellSize * (vec3(cell_co + adaptiveCellOffset) + 0.5);
+
+ vec3 velocity;
+ velocity.x = texelFetch(velocityX, cell_co, 0).r;
+ velocity.y = texelFetch(velocityY, cell_co, 0).r;
+ velocity.z = texelFetch(velocityZ, cell_co, 0).r;
+
+ finalColor = vec4(weight_to_color(length(velocity)), 1.0);
+
+#ifdef USE_NEEDLE
+ mat3 rot_mat = rotation_from_vector(velocity);
+ vec3 rotated_pos = rot_mat * corners[indices[gl_VertexID % 12]];
+ pos += rotated_pos * length(velocity) * displaySize * cellSize;
+#else
+ pos += ((gl_VertexID % 2) == 1) ? velocity * displaySize * cellSize : vec3(0.0);
+#endif
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl
new file mode 100644
index 00000000000..39d0012574c
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl
@@ -0,0 +1,20 @@
+
+in vec3 finalColor;
+flat in float edgeSharpness;
+
+flat in vec2 edgeStart;
+noperspective in vec2 edgePos;
+
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 lineOutput;
+
+void main()
+{
+ if (edgeSharpness < 0.0) {
+ discard;
+ }
+
+ lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos);
+ fragColor.rgb = finalColor;
+ fragColor.a = 1.0;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_geom.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_geom.glsl
new file mode 100644
index 00000000000..346c9d83a9e
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/wireframe_geom.glsl
@@ -0,0 +1,61 @@
+
+/* This shader is only used for edge selection and OSX workaround for large wires. */
+
+layout(lines) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+in vec3 finalColor_g[];
+in float edgeSharpness_g[];
+
+#ifndef SELECT_EDGES
+out vec3 finalColor;
+flat out float edgeSharpness;
+
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
+#endif
+
+void do_vertex(const int i, float coord, vec2 offset)
+{
+#ifndef SELECT_EDGES
+ /* TODO */
+ edgePos = edgeStart = vec2(0);
+ edgeSharpness = edgeSharpness_g[i];
+ finalColor = finalColor_g[i];
+#endif
+ gl_Position = gl_in[i].gl_Position;
+ /* Multiply offset by 2 because gl_Position range is [-1..1]. */
+ gl_Position.xy += offset * 2.0 * gl_Position.w;
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_set_clip_distance(gl_in[i].gl_ClipDistance);
+#endif
+ EmitVertex();
+}
+
+void main()
+{
+ vec2 ss_pos[2];
+ ss_pos[0] = gl_in[0].gl_Position.xy / gl_in[0].gl_Position.w;
+ ss_pos[1] = gl_in[1].gl_Position.xy / gl_in[1].gl_Position.w;
+
+ vec2 line = ss_pos[0] - ss_pos[1];
+ line = abs(line) * sizeViewport.xy;
+
+ float half_size = sizePixel * 0.5;
+
+ vec3 edge_ofs = vec3(half_size * sizeViewportInv.xy, 0.0);
+
+ bool horizontal = line.x > line.y;
+ edge_ofs = (horizontal) ? edge_ofs.zyz : edge_ofs.xzz;
+
+ if (edgeSharpness_g[0] < 0.0) {
+ return;
+ }
+
+ do_vertex(0, half_size, edge_ofs.xy);
+ do_vertex(0, -half_size, -edge_ofs.xy);
+ do_vertex(1, half_size, edge_ofs.xy);
+ do_vertex(1, -half_size, -edge_ofs.xy);
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
new file mode 100644
index 00000000000..78ce8fd8a8f
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
@@ -0,0 +1,144 @@
+
+uniform float wireStepParam;
+
+in vec3 pos;
+in vec3 nor;
+in float wd; /* wiredata */
+
+float get_edge_sharpness(float wd)
+{
+ return ((wd == 0.0) ? -1.5 : wd) + wireStepParam;
+}
+
+/* Geometry shader version */
+#if defined(SELECT_EDGES) || defined(USE_GEOM)
+out vec3 finalColor_g;
+out float edgeSharpness_g;
+
+#else /* USE_GEOM */
+
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
+
+out vec3 finalColor;
+flat out float edgeSharpness;
+# define finalColor_g finalColor
+# define edgeSharpness_g edgeSharpness
+
+#endif /* SELECT_EDGES */
+
+uniform bool useColoring;
+uniform bool isTransform;
+uniform bool isObjectColor;
+uniform bool isRandomColor;
+
+void wire_color_get(out vec3 rim_col, out vec3 wire_col)
+{
+ int flag = int(abs(ObjectInfo.w));
+ bool is_selected = (flag & DRW_BASE_SELECTED) != 0;
+ bool is_from_dupli = (flag & DRW_BASE_FROM_DUPLI) != 0;
+ bool is_from_set = (flag & DRW_BASE_FROM_SET) != 0;
+ bool is_active = (flag & DRW_BASE_ACTIVE) != 0;
+
+ if (is_from_set) {
+ rim_col = colorDupli.rgb;
+ wire_col = colorDupli.rgb;
+ }
+ else if (is_from_dupli) {
+ if (is_selected) {
+ if (isTransform) {
+ rim_col = colorTransform.rgb;
+ }
+ else {
+ rim_col = colorDupliSelect.rgb;
+ }
+ }
+ else {
+ rim_col = colorDupli.rgb;
+ }
+ wire_col = colorDupli.rgb;
+ }
+ else if (is_selected && useColoring) {
+ if (isTransform) {
+ rim_col = colorTransform.rgb;
+ }
+ else if (is_active) {
+ rim_col = colorActive.rgb;
+ }
+ else {
+ rim_col = colorSelect.rgb;
+ }
+ wire_col = colorWire.rgb;
+ }
+ else {
+ rim_col = colorWire.rgb;
+ wire_col = colorBackground.rgb;
+ }
+}
+
+vec3 hsv_to_rgb(vec3 hsv)
+{
+ vec3 nrgb = abs(hsv.x * 6.0 - vec3(3.0, 2.0, 4.0)) * vec3(1, -1, -1) + vec3(-1, 2, 2);
+ nrgb = clamp(nrgb, 0.0, 1.0);
+ return ((nrgb - 1.0) * hsv.y + 1.0) * hsv.z;
+}
+
+void wire_object_color_get(out vec3 rim_col, out vec3 wire_col)
+{
+ int flag = int(abs(ObjectInfo.w));
+ bool is_selected = (flag & DRW_BASE_SELECTED) != 0;
+
+ if (isObjectColor) {
+ rim_col = wire_col = ObjectColor.rgb * 0.5;
+ }
+ else {
+ float hue = ObjectInfo.z;
+ vec3 hsv = vec3(hue, 0.75, 0.8);
+ rim_col = wire_col = hsv_to_rgb(hsv);
+ }
+
+ if (is_selected && useColoring) {
+ /* "Normalize" color. */
+ wire_col += 1e-4; /* Avoid division by 0. */
+ float brightness = max(wire_col.x, max(wire_col.y, wire_col.z));
+ wire_col *= 0.5 / brightness;
+ rim_col += 0.75;
+ }
+ else {
+ rim_col *= 0.5;
+ wire_col += 0.5;
+ }
+}
+
+void main()
+{
+ vec3 wpos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(wpos);
+
+#if !(defined(SELECT_EDGES) || defined(USE_GEOM))
+ /* Convert to screen position [0..sizeVp]. */
+ edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+#endif
+
+ edgeSharpness_g = get_edge_sharpness(wd);
+
+ vec3 rim_col, wire_col;
+ if (isObjectColor || isRandomColor) {
+ wire_object_color_get(rim_col, wire_col);
+ }
+ else {
+ wire_color_get(rim_col, wire_col);
+ }
+
+ vec3 wnor = normalize(normal_object_to_world(nor));
+ float facing = dot(wnor, ViewMatrixInverse[2].xyz);
+ facing = clamp(abs(facing), 0.0, 1.0);
+
+ vec3 final_front_col = mix(rim_col, wire_col, 0.4);
+ vec3 final_rim_col = mix(rim_col, wire_col, 0.1);
+ finalColor_g = mix(final_rim_col, final_front_col, facing);
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(wpos);
+#endif
+}