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
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')
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c50
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_antialiasing.c184
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c2338
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_curve.c127
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_mesh.c419
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_text.c201
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c491
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.h28
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c1586
-rw-r--r--source/blender/draw/engines/overlay/overlay_facing.c64
-rw-r--r--source/blender/draw/engines/overlay/overlay_grid.c220
-rw-r--r--source/blender/draw/engines/overlay/overlay_image.c470
-rw-r--r--source/blender/draw/engines/overlay/overlay_lattice.c78
-rw-r--r--source/blender/draw/engines/overlay/overlay_metaball.c143
-rw-r--r--source/blender/draw/engines/overlay/overlay_motion_path.c231
-rw-r--r--source/blender/draw/engines/overlay/overlay_outline.c353
-rw-r--r--source/blender/draw/engines/overlay/overlay_paint.c211
-rw-r--r--source/blender/draw/engines/overlay/overlay_particle.c217
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.h585
-rw-r--r--source/blender/draw/engines/overlay/overlay_sculpt.c65
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader.c1337
-rw-r--r--source/blender/draw/engines/overlay/overlay_wireframe.c231
-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
-rw-r--r--source/blender/draw/engines/select/select_engine.c4
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl2
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c63
103 files changed, 13504 insertions, 57 deletions
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index 0dd1a4fd686..fcbe227ca1b 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -46,8 +46,8 @@ typedef struct BASIC_StorageList {
} BASIC_StorageList;
typedef struct BASIC_PassList {
- struct DRWPass *depth_pass;
- struct DRWPass *depth_pass_cull;
+ struct DRWPass *depth_pass[2];
+ struct DRWPass *depth_pass_cull[2];
} BASIC_PassList;
typedef struct BASIC_Data {
@@ -70,8 +70,8 @@ static struct {
} e_data = {{{NULL}}}; /* Engine data */
typedef struct BASIC_PrivateData {
- DRWShadingGroup *depth_shgrp;
- DRWShadingGroup *depth_shgrp_cull;
+ DRWShadingGroup *depth_shgrp[2];
+ DRWShadingGroup *depth_shgrp_cull[2];
} BASIC_PrivateData; /* Transient data */
/* Functions */
@@ -97,24 +97,21 @@ static void basic_cache_init(void *vedata)
if (!stl->g_data) {
/* Alloc transient pointers */
- stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
}
- {
- psl->depth_pass = DRW_pass_create("Depth Pass",
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
- stl->g_data->depth_shgrp = DRW_shgroup_create(sh_data->depth, psl->depth_pass);
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(stl->g_data->depth_shgrp, DRW_STATE_CLIP_PLANES);
- }
+ /* Twice for normal and infront objects. */
+ for (int i = 0; i < 2; i++) {
+ DRWState clip_state = (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? DRW_STATE_CLIP_PLANES : 0;
+ DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
+ DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- psl->depth_pass_cull = DRW_pass_create("Depth Pass Cull",
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
- DRW_STATE_CULL_BACK);
- stl->g_data->depth_shgrp_cull = DRW_shgroup_create(sh_data->depth, psl->depth_pass_cull);
- if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
- DRW_shgroup_state_enable(stl->g_data->depth_shgrp_cull, DRW_STATE_CLIP_PLANES);
- }
+ DRW_PASS_CREATE(psl->depth_pass[i], state | clip_state | infront_state);
+ stl->g_data->depth_shgrp[i] = DRW_shgroup_create(sh_data->depth, psl->depth_pass[i]);
+
+ state |= DRW_STATE_CULL_BACK;
+ DRW_PASS_CREATE(psl->depth_pass_cull[i], state | clip_state | infront_state);
+ stl->g_data->depth_shgrp_cull[i] = DRW_shgroup_create(sh_data->depth, psl->depth_pass_cull[i]);
}
}
@@ -128,6 +125,8 @@ static void basic_cache_populate(void *vedata, Object *ob)
return;
}
+ bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+
const DRWContextState *draw_ctx = DRW_context_state_get();
if (ob != draw_ctx->object_edit) {
for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) {
@@ -138,7 +137,7 @@ static void basic_cache_populate(void *vedata, Object *ob)
const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
if (draw_as == PART_DRAW_PATH) {
struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL);
- DRW_shgroup_call(stl->g_data->depth_shgrp, hairs, NULL);
+ DRW_shgroup_call(stl->g_data->depth_shgrp[do_in_front], hairs, NULL);
}
}
}
@@ -155,7 +154,7 @@ static void basic_cache_populate(void *vedata, Object *ob)
/* Avoid losing flat objects when in ortho views (see T56549) */
struct GPUBatch *geom = DRW_cache_object_all_edges_get(ob);
if (geom) {
- DRW_shgroup_call(stl->g_data->depth_shgrp, geom, ob);
+ DRW_shgroup_call(stl->g_data->depth_shgrp[do_in_front], geom, ob);
}
return;
}
@@ -165,7 +164,8 @@ static void basic_cache_populate(void *vedata, Object *ob)
!DRW_state_is_image_render();
const bool do_cull = (draw_ctx->v3d &&
(draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING));
- DRWShadingGroup *shgrp = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp;
+ DRWShadingGroup *shgrp = (do_cull) ? stl->g_data->depth_shgrp_cull[do_in_front] :
+ stl->g_data->depth_shgrp[do_in_front];
if (use_sculpt_pbvh) {
DRW_shgroup_call_sculpt(shgrp, ob, false, false, false);
@@ -189,8 +189,10 @@ static void basic_draw_scene(void *vedata)
{
BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl;
- DRW_draw_pass(psl->depth_pass);
- DRW_draw_pass(psl->depth_pass_cull);
+ DRW_draw_pass(psl->depth_pass[0]);
+ DRW_draw_pass(psl->depth_pass_cull[0]);
+ DRW_draw_pass(psl->depth_pass[1]);
+ DRW_draw_pass(psl->depth_pass_cull[1]);
}
static void basic_engine_free(void)
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 9554e9c0275..a1a1f7cc389 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -33,8 +33,6 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
-#include "draw_mode_engines.h"
-
#include "GPU_texture.h"
#include "gpencil_engine.h"
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 36bc205f41a..04ed19830ed 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -25,6 +25,8 @@
#include "GPU_batch.h"
+extern DrawEngineType draw_engine_gpencil_type;
+
struct GPENCIL_Data;
struct GPENCIL_StorageList;
struct MaterialGPencilStyle;
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index 81e48eb05f2..8c126310ea2 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -29,8 +29,6 @@
#include "DEG_depsgraph_query.h"
-#include "draw_mode_engines.h"
-
#include "RE_pipeline.h"
#include "gpencil_engine.h"
diff --git a/source/blender/draw/engines/overlay/overlay_antialiasing.c b/source/blender/draw/engines/overlay/overlay_antialiasing.c
new file mode 100644
index 00000000000..54a598633fb
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_antialiasing.c
@@ -0,0 +1,184 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Overlay antialiasing:
+ *
+ * Most of the overlays are wires which causes a lot of flickering in motions
+ * due to aliasing problems.
+ *
+ * Our goal is to have a technique that works with single sample per pixel
+ * to avoid extra cost of managing MSAA or additional texture buffers and jitters.
+ *
+ * To solve this we use a simple and effective post-process AA. The technique
+ * goes like this:
+ *
+ * - During wireframe rendering, we output the line color, the line direction
+ * and the distance from the line for the pixel center.
+ *
+ * - Then, in a post process pass, for each pixels we gather all lines in a search area
+ * that could cover (even partially) the center pixel.
+ * We compute the coverage of each line and do a sorted alpha compositing of them.
+ *
+ * This technique has one major shortcoming compared to MSAA:
+ * - It handles (initial) partial visibility poorly (because of single sample). This makes
+ * overlaping / crossing wires a bit too thin at their intersection.
+ * Wireframe meshes overlaid over solid meshes can have half of the edge missing due to
+ * z-fighting (this has workaround).
+ * Another manifestation of this, is fickering of really dense wireframe if using small
+ * line thickness (also has workaround).
+ *
+ * The pros of this approach are many:
+ * - Works without geometry shader.
+ * - Can inflate line thickness.
+ * - Coverage is very close to perfect and can even be filtered (Blackman-Harris, gaussian).
+ * - Wires can "bleed" / overlap non-line objects since the filter is in screenspace.
+ * - Only uses one additional lightweight fullscreen buffer (compared to MSAA/SMAA).
+ * - No convergence time (compared to TAA).
+ */
+
+#include "DRW_render.h"
+
+#include "ED_screen.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_antialiasing_reset(OVERLAY_Data *vedata)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ pd->antialiasing.sample = 0;
+}
+
+void OVERLAY_antialiasing_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ if (!DRW_state_is_fbo()) {
+ /* Use default view */
+ pd->view_default = (DRWView *)DRW_view_default_get();
+ pd->antialiasing.enabled = false;
+ return;
+ }
+
+ /* TODO Get real userpref option and remove MSAA buffer. */
+ pd->antialiasing.enabled = dtxl->multisample_color != NULL;
+
+ /* Use default view */
+ pd->view_default = (DRWView *)DRW_view_default_get();
+
+ if (pd->antialiasing.enabled) {
+ DRW_texture_ensure_fullscreen_2d(&txl->overlay_color_tx, GPU_RGBA8, DRW_TEX_FILTER);
+ DRW_texture_ensure_fullscreen_2d(&txl->overlay_line_tx, GPU_RGBA8, 0);
+
+ GPU_framebuffer_ensure_config(
+ &fbl->overlay_color_only_fb,
+ {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx)});
+ GPU_framebuffer_ensure_config(
+ &fbl->overlay_default_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx)});
+ GPU_framebuffer_ensure_config(&fbl->overlay_line_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx),
+ GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)});
+ }
+ else {
+ /* Just a copy of the defaults framebuffers. */
+ GPU_framebuffer_ensure_config(&fbl->overlay_color_only_fb,
+ {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+ GPU_framebuffer_ensure_config(
+ &fbl->overlay_default_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+ GPU_framebuffer_ensure_config(
+ &fbl->overlay_line_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+ }
+}
+
+void OVERLAY_antialiasing_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ OVERLAY_PassList *psl = vedata->psl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ if (pd->antialiasing.enabled) {
+ DRW_PASS_CREATE(psl->antialiasing_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL);
+
+ sh = OVERLAY_shader_antialiasing();
+ grp = DRW_shgroup_create(sh, psl->antialiasing_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture_ref(grp, "depthTex", &dtxl->depth);
+ DRW_shgroup_uniform_texture_ref(grp, "colorTex", &txl->overlay_color_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "lineTex", &txl->overlay_line_tx);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+}
+
+void OVERLAY_antialiasing_cache_finish(OVERLAY_Data *vedata)
+{
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ if (pd->antialiasing.enabled) {
+ GPU_framebuffer_ensure_config(&fbl->overlay_in_front_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
+ GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx)});
+ }
+ else {
+ GPU_framebuffer_ensure_config(
+ &fbl->overlay_in_front_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+ }
+}
+
+void OVERLAY_antialiasing_start(OVERLAY_Data *vedata)
+{
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ if (pd->antialiasing.enabled) {
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ GPU_framebuffer_bind(fbl->overlay_line_fb);
+ GPU_framebuffer_clear_color(fbl->overlay_line_fb, clear_col);
+
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+}
+
+void OVERLAY_antialiasing_end(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (pd->antialiasing.enabled) {
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->antialiasing_ps);
+
+ GPU_framebuffer_bind(dfbl->default_fb);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
new file mode 100644
index 00000000000..c749d902f86
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -0,0 +1,2338 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_object_types.h"
+
+#include "DRW_render.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_armature.h"
+#include "BKE_modifier.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_armature.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h"
+
+#include "draw_common.h"
+#include "draw_manager_text.h"
+
+#include "overlay_private.h"
+
+#define BONE_VAR(eBone, pchan, var) ((eBone) ? (eBone->var) : (pchan->var))
+#define BONE_FLAG(eBone, pchan) ((eBone) ? (eBone->flag) : (pchan->bone->flag))
+
+#define PT_DEFAULT_RAD 0.05f /* radius of the point batch. */
+
+typedef struct ArmatureDrawContext {
+ /* Current armature object */
+ Object *ob;
+ /* bArmature *arm; */ /* TODO */
+
+ union {
+ struct {
+ DRWCallBuffer *outline;
+ DRWCallBuffer *solid;
+ DRWCallBuffer *wire;
+ };
+ struct {
+ DRWCallBuffer *envelope_outline;
+ DRWCallBuffer *envelope_solid;
+ DRWCallBuffer *envelope_distance;
+ };
+ struct {
+ DRWCallBuffer *stick;
+ };
+ };
+
+ DRWCallBuffer *dof_lines;
+ DRWCallBuffer *dof_sphere;
+ DRWCallBuffer *point_solid;
+ DRWCallBuffer *point_outline;
+ DRWShadingGroup *custom_solid;
+ DRWShadingGroup *custom_outline;
+ DRWShadingGroup *custom_wire;
+ GHash *custom_shapes_ghash;
+
+ OVERLAY_ExtraCallBuffers *extras;
+
+ /**
+ * Follow `TH_*` naming except for mixed colors.
+ */
+ struct {
+ float select[4];
+ float edge_select[4];
+ float bone_select[4]; /* tint */
+ float wire[4];
+ float wire_edit[4];
+ float bone_solid[4];
+ float bone_active_unselect[4]; /* mix */
+ float bone_pose[4];
+ float bone_pose_active[4];
+ float bone_pose_active_unselect[4]; /* mix */
+ float text_hi[4];
+ float text[4];
+ float vertex_select[4];
+ float vertex[4];
+ } color;
+
+ /* not a theme, this is an override */
+ const float *const_color;
+ float const_wire;
+
+ bool do_relations;
+ bool transparent;
+ bool show_relations;
+
+ const ThemeWireColor *bcolor; /* pchan color */
+} ArmatureDrawContext;
+
+/**
+ * Return true if armature should be handled by the pose mode engine.
+ */
+bool OVERLAY_armature_is_pose_mode(Object *ob, const DRWContextState *draw_ctx)
+{
+ Object *active_ob = draw_ctx->obact;
+
+ /* Pose armature is handled by pose mode engine. */
+ if (((ob == active_ob) || (ob->mode & OB_MODE_POSE)) &&
+ ((draw_ctx->object_mode & OB_MODE_POSE) != 0)) {
+ return true;
+ }
+
+ /* Armature parent is also handled by pose mode engine. */
+ if ((active_ob != NULL) && ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) != 0)) {
+ if (ob == draw_ctx->object_pose) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ pd->armature.transparent = (draw_ctx->v3d->shading.type == OB_WIRE) ||
+ XRAY_FLAG_ENABLED(draw_ctx->v3d);
+ pd->armature.show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0);
+ pd->armature.do_pose_fade_geom = (pd->overlay.flag & V3D_OVERLAY_BONE_SELECT) &&
+ ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) == 0) &&
+ draw_ctx->object_pose != NULL;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ADD;
+ DRW_PASS_CREATE(psl->armature_transp_ps, state | pd->clipping_state);
+
+ if (pd->armature.do_pose_fade_geom) {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->armature_bone_select_ps, state | pd->clipping_state);
+
+ float alpha = pd->overlay.xray_alpha_bone;
+ struct GPUShader *sh = OVERLAY_shader_uniform_color();
+ DRWShadingGroup *grp;
+
+ pd->armature_bone_select_act_grp = grp = DRW_shgroup_create(sh, psl->armature_bone_select_ps);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", (float[4]){0.0f, 0.0f, 0.0f, alpha});
+
+ pd->armature_bone_select_grp = grp = DRW_shgroup_create(sh, psl->armature_bone_select_ps);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", (float[4]){0.0f, 0.0f, 0.0f, pow(alpha, 4)});
+ }
+
+ for (int i = 0; i < 2; i++) {
+ struct GPUShader *sh;
+ struct GPUVertFormat *format;
+ DRWShadingGroup *grp = NULL;
+
+ OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
+ OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[i];
+ DRWPass **p_armature_ps = &psl->armature_ps[i];
+
+ cb->custom_shapes_ghash = BLI_ghash_ptr_new(__func__);
+
+ DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK |
+ (pd->armature.transparent ? DRW_STATE_BLEND_ALPHA : DRW_STATE_WRITE_DEPTH);
+ DRW_PASS_CREATE(*p_armature_ps, state | pd->clipping_state | infront_state);
+
+ DRWPass *armature_ps = *p_armature_ps;
+
+#define BUF_INSTANCE DRW_shgroup_call_buffer_instance
+#define BUF_LINE(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_LINES)
+
+ {
+ format = formats->instance_bone;
+
+ sh = OVERLAY_shader_armature_sphere(false);
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", pd->armature.transparent ? 0.4f : 1.0f);
+ cb->point_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get());
+
+ sh = OVERLAY_shader_armature_sphere(true);
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_disable(grp, DRW_STATE_CULL_BACK);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ cb->point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get());
+
+ sh = OVERLAY_shader_armature_shape(false);
+ cb->custom_solid = grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", pd->armature.transparent ? 0.6f : 1.0f);
+ cb->box_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get());
+ cb->octa_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get());
+
+ sh = OVERLAY_shader_armature_shape(true);
+ cb->custom_outline = grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_disable(grp, DRW_STATE_CULL_BACK);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ cb->box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get());
+ cb->octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get());
+ }
+ {
+ format = formats->instance_extra;
+
+ sh = OVERLAY_shader_armature_degrees_of_freedom();
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ cb->dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get());
+
+ grp = DRW_shgroup_create(sh, psl->armature_transp_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ cb->dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get());
+ }
+ {
+ format = formats->instance_bone_stick;
+
+ sh = OVERLAY_shader_armature_stick();
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ cb->stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get());
+ }
+ {
+ format = formats->instance_bone_envelope;
+
+ sh = OVERLAY_shader_armature_envelope(false);
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "isDistance", false);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", pd->armature.transparent ? 0.6f : 1.0f);
+ cb->envelope_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+
+ format = formats->instance_bone_envelope_outline;
+
+ sh = OVERLAY_shader_armature_envelope(true);
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_disable(grp, DRW_STATE_CULL_BACK);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ cb->envelope_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_outline_get());
+
+ format = formats->instance_bone_envelope_distance;
+
+ sh = OVERLAY_shader_armature_envelope(false);
+ grp = DRW_shgroup_create(sh, psl->armature_transp_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "isDistance", true);
+ DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT);
+ cb->envelope_distance = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+ }
+ {
+ format = formats->pos_color;
+
+ sh = OVERLAY_shader_armature_wire();
+ grp = DRW_shgroup_create(sh, armature_ps);
+ cb->wire = BUF_LINE(grp, format);
+ }
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Shader Groups (DRW_shgroup)
+ * \{ */
+
+static void bone_instance_data_set_angle_minmax(BoneInstanceData *data,
+ const float aminx,
+ const float aminz,
+ const float amaxx,
+ const float amaxz)
+{
+ data->amin_a = aminx;
+ data->amin_b = aminz;
+ data->amax_a = amaxx;
+ data->amax_b = amaxz;
+}
+
+/* Encode 2 units float with byte precision into a float. */
+static float encode_2f_to_float(float a, float b)
+{
+ CLAMP(a, 0.0f, 1.0f);
+ CLAMP(b, 0.0f, 2.0f); /* Can go up to 2. Needed for wire size. */
+ return (float)((int)(a * 255) | ((int)(b * 255) << 8));
+}
+
+void OVERLAY_bone_instance_data_set_color_hint(BoneInstanceData *data, const float hint_color[4])
+{
+ /* Encoded color into 2 floats to be able to use the obmat to color the custom bones. */
+ data->color_hint_a = encode_2f_to_float(hint_color[0], hint_color[1]);
+ data->color_hint_b = encode_2f_to_float(hint_color[2], hint_color[3]);
+}
+
+void OVERLAY_bone_instance_data_set_color(BoneInstanceData *data, const float bone_color[4])
+{
+ /* Encoded color into 2 floats to be able to use the obmat to color the custom bones. */
+ data->color_a = encode_2f_to_float(bone_color[0], bone_color[1]);
+ data->color_b = encode_2f_to_float(bone_color[2], bone_color[3]);
+}
+
+/* Octahedral */
+static void drw_shgroup_bone_octahedral(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float bone_color[4],
+ const float hint_color[4],
+ const float outline_color[4])
+{
+ BoneInstanceData inst_data;
+ mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+ if (ctx->solid) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
+ DRW_buffer_add_entry_struct(ctx->solid, &inst_data);
+ }
+ if (outline_color[3] > 0.0f) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+ DRW_buffer_add_entry_struct(ctx->outline, &inst_data);
+ }
+}
+
+/* Box / B-Bone */
+static void drw_shgroup_bone_box(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float bone_color[4],
+ const float hint_color[4],
+ const float outline_color[4])
+{
+ BoneInstanceData inst_data;
+ mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+ if (ctx->solid) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
+ DRW_buffer_add_entry_struct(ctx->solid, &inst_data);
+ }
+ if (outline_color[3] > 0.0f) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+ DRW_buffer_add_entry_struct(ctx->outline, &inst_data);
+ }
+}
+
+/* Wire */
+static void drw_shgroup_bone_wire(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float color[4])
+{
+ float head[3], tail[3];
+ mul_v3_m4v3(head, ctx->ob->obmat, bone_mat[3]);
+ add_v3_v3v3(tail, bone_mat[3], bone_mat[1]);
+ mul_m4_v3(ctx->ob->obmat, tail);
+
+ DRW_buffer_add_entry(ctx->wire, head, color);
+ DRW_buffer_add_entry(ctx->wire, tail, color);
+}
+
+/* Stick */
+static void drw_shgroup_bone_stick(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float col_wire[4],
+ const float col_bone[4],
+ const float col_head[4],
+ const float col_tail[4])
+{
+ float head[3], tail[3];
+ mul_v3_m4v3(head, ctx->ob->obmat, bone_mat[3]);
+ add_v3_v3v3(tail, bone_mat[3], bone_mat[1]);
+ mul_m4_v3(ctx->ob->obmat, tail);
+
+ DRW_buffer_add_entry(ctx->stick, head, tail, col_wire, col_bone, col_head, col_tail);
+}
+
+/* Envelope */
+static void drw_shgroup_bone_envelope_distance(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float *radius_head,
+ const float *radius_tail,
+ const float *distance)
+{
+ if (ctx->envelope_distance) {
+ float head_sph[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sph[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+ float xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ /* Still less operation than m4 multiplication. */
+ mul_m4_v4(bone_mat, head_sph);
+ mul_m4_v4(bone_mat, tail_sph);
+ mul_m4_v4(bone_mat, xaxis);
+ mul_m4_v4(ctx->ob->obmat, head_sph);
+ mul_m4_v4(ctx->ob->obmat, tail_sph);
+ mul_m4_v4(ctx->ob->obmat, xaxis);
+ sub_v3_v3(xaxis, head_sph);
+ head_sph[3] = *radius_head;
+ head_sph[3] += *distance;
+ tail_sph[3] = *radius_tail;
+ tail_sph[3] += *distance;
+ DRW_buffer_add_entry(ctx->envelope_distance, head_sph, tail_sph, xaxis);
+ }
+}
+
+static void drw_shgroup_bone_envelope(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float bone_col[4],
+ const float hint_col[4],
+ const float outline_col[4],
+ const float *radius_head,
+ const float *radius_tail)
+{
+ float head_sph[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sph[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+ float xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ /* Still less operation than m4 multiplication. */
+ mul_m4_v4(bone_mat, head_sph);
+ mul_m4_v4(bone_mat, tail_sph);
+ mul_m4_v4(bone_mat, xaxis);
+ mul_m4_v4(ctx->ob->obmat, head_sph);
+ mul_m4_v4(ctx->ob->obmat, tail_sph);
+ mul_m4_v4(ctx->ob->obmat, xaxis);
+ head_sph[3] = *radius_head;
+ tail_sph[3] = *radius_tail;
+
+ if (head_sph[3] < 0.0f || tail_sph[3] < 0.0f) {
+ BoneInstanceData inst_data;
+ if (head_sph[3] < 0.0f) {
+ /* Draw Tail only */
+ scale_m4_fl(inst_data.mat, tail_sph[3] / PT_DEFAULT_RAD);
+ copy_v3_v3(inst_data.mat[3], tail_sph);
+ }
+ else {
+ /* Draw Head only */
+ scale_m4_fl(inst_data.mat, head_sph[3] / PT_DEFAULT_RAD);
+ copy_v3_v3(inst_data.mat[3], head_sph);
+ }
+
+ if (ctx->point_solid) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, bone_col);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_col);
+ DRW_buffer_add_entry_struct(ctx->point_solid, &inst_data);
+ }
+ if (outline_col[3] > 0.0f) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_col);
+ DRW_buffer_add_entry_struct(ctx->point_outline, &inst_data);
+ }
+ }
+ else {
+ /* Draw Body */
+ float tmp_sph[4];
+ float len = len_v3v3(tail_sph, head_sph);
+ float fac_head = (len - head_sph[3]) / len;
+ float fac_tail = (len - tail_sph[3]) / len;
+ /* Small epsilon to avoid problem with float precision in shader. */
+ if (len > (tail_sph[3] + head_sph[3]) + 1e-8f) {
+ copy_v4_v4(tmp_sph, head_sph);
+ interp_v4_v4v4(head_sph, tail_sph, head_sph, fac_head);
+ interp_v4_v4v4(tail_sph, tmp_sph, tail_sph, fac_tail);
+ if (ctx->envelope_solid) {
+ DRW_buffer_add_entry(ctx->envelope_solid, head_sph, tail_sph, bone_col, hint_col, xaxis);
+ }
+ if (outline_col[3] > 0.0f) {
+ DRW_buffer_add_entry(ctx->envelope_outline, head_sph, tail_sph, outline_col, xaxis);
+ }
+ }
+ else {
+ /* Distance between endpoints is too small for a capsule. Draw a Sphere instead. */
+ float fac = max_ff(fac_head, 1.0f - fac_tail);
+ interp_v4_v4v4(tmp_sph, tail_sph, head_sph, clamp_f(fac, 0.0f, 1.0f));
+
+ BoneInstanceData inst_data;
+ scale_m4_fl(inst_data.mat, tmp_sph[3] / PT_DEFAULT_RAD);
+ copy_v3_v3(inst_data.mat[3], tmp_sph);
+ if (ctx->point_solid) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, bone_col);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_col);
+ DRW_buffer_add_entry_struct(ctx->point_solid, &inst_data);
+ }
+ if (outline_col[3] > 0.0f) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_col);
+ DRW_buffer_add_entry_struct(ctx->point_outline, &inst_data);
+ }
+ }
+ }
+}
+
+/* Custom (geometry) */
+
+extern void drw_batch_cache_validate(Object *custom);
+extern void drw_batch_cache_generate_requested(Object *custom);
+
+BLI_INLINE DRWCallBuffer *custom_bone_instance_shgroup(ArmatureDrawContext *ctx,
+ DRWShadingGroup *grp,
+ struct GPUBatch *custom_geom)
+{
+ DRWCallBuffer *buf = BLI_ghash_lookup(ctx->custom_shapes_ghash, custom_geom);
+ if (buf == NULL) {
+ OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
+ buf = DRW_shgroup_call_buffer_instance(grp, formats->instance_bone, custom_geom);
+ BLI_ghash_insert(ctx->custom_shapes_ghash, custom_geom, buf);
+ }
+ return buf;
+}
+
+static void drw_shgroup_bone_custom_solid(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float bone_color[4],
+ const float hint_color[4],
+ const float outline_color[4],
+ Object *custom)
+{
+ /* TODO(fclem) arg... less than ideal but we never iter on this object
+ * to assure batch cache is valid. */
+ drw_batch_cache_validate(custom);
+
+ struct GPUBatch *surf = DRW_cache_object_surface_get(custom);
+ struct GPUBatch *edges = DRW_cache_object_edge_detection_get(custom, NULL);
+ struct GPUBatch *ledges = DRW_cache_object_loose_edges_get(custom);
+ BoneInstanceData inst_data;
+ DRWCallBuffer *buf;
+
+ if (surf || edges || ledges) {
+ mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+ }
+
+ if (surf && ctx->custom_solid) {
+ buf = custom_bone_instance_shgroup(ctx, ctx->custom_solid, surf);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
+ OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
+ DRW_buffer_add_entry_struct(buf, inst_data.mat);
+ }
+
+ if (edges && ctx->custom_outline) {
+ buf = custom_bone_instance_shgroup(ctx, ctx->custom_outline, edges);
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+ DRW_buffer_add_entry_struct(buf, inst_data.mat);
+ }
+
+ if (ledges) {
+ buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, ledges);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, outline_color);
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+ DRW_buffer_add_entry_struct(buf, inst_data.mat);
+ }
+
+ /* TODO(fclem) needs to be moved elsewhere. */
+ drw_batch_cache_generate_requested(custom);
+}
+
+static void drw_shgroup_bone_custom_wire(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float color[4],
+ Object *custom)
+{
+ /* TODO(fclem) arg... less than ideal but we never iter on this object
+ * to assure batch cache is valid. */
+ drw_batch_cache_validate(custom);
+
+ struct GPUBatch *geom = DRW_cache_object_all_edges_get(custom);
+
+ if (geom) {
+ DRWCallBuffer *buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, geom);
+ BoneInstanceData inst_data;
+ mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, color);
+ OVERLAY_bone_instance_data_set_color(&inst_data, color);
+ DRW_buffer_add_entry_struct(buf, inst_data.mat);
+ }
+
+ /* TODO(fclem) needs to be moved elsewhere. */
+ drw_batch_cache_generate_requested(custom);
+}
+
+static void drw_shgroup_bone_custom_empty(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float color[4],
+ Object *custom)
+{
+ float final_color[4] = {color[0], color[1], color[2], 1.0f};
+ float mat[4][4];
+ mul_m4_m4m4(mat, ctx->ob->obmat, bone_mat);
+
+ switch (custom->empty_drawtype) {
+ case OB_PLAINAXES:
+ case OB_SINGLE_ARROW:
+ case OB_CUBE:
+ case OB_CIRCLE:
+ case OB_EMPTY_SPHERE:
+ case OB_EMPTY_CONE:
+ case OB_ARROWS:
+ OVERLAY_empty_shape(
+ ctx->extras, mat, custom->empty_drawsize, custom->empty_drawtype, final_color);
+ break;
+ case OB_EMPTY_IMAGE:
+ break;
+ }
+}
+
+/* Head and tail sphere */
+static void drw_shgroup_bone_point(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float bone_color[4],
+ const float hint_color[4],
+ const float outline_color[4])
+{
+ BoneInstanceData inst_data;
+ mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+ if (ctx->point_solid) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
+ OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
+ DRW_buffer_add_entry_struct(ctx->point_solid, &inst_data);
+ }
+ if (outline_color[3] > 0.0f) {
+ OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+ DRW_buffer_add_entry_struct(ctx->point_outline, &inst_data);
+ }
+}
+
+/* Axes */
+static void drw_shgroup_bone_axes(ArmatureDrawContext *ctx,
+ const float (*bone_mat)[4],
+ const float color[4])
+{
+ float mat[4][4];
+ mul_m4_m4m4(mat, ctx->ob->obmat, bone_mat);
+ /* Move to bone tail. */
+ add_v3_v3(mat[3], mat[1]);
+ OVERLAY_empty_shape(ctx->extras, mat, 0.25f, OB_ARROWS, color);
+}
+
+/* Relationship lines */
+static void drw_shgroup_bone_relationship_lines_ex(ArmatureDrawContext *ctx,
+ const float start[3],
+ const float end[3],
+ const float color[4])
+{
+ float s[3], e[3];
+ mul_v3_m4v3(s, ctx->ob->obmat, start);
+ mul_v3_m4v3(e, ctx->ob->obmat, end);
+ /* reverse order to have less stipple overlap */
+ OVERLAY_extra_line_dashed(ctx->extras, s, e, color);
+}
+
+static void drw_shgroup_bone_relationship_lines(ArmatureDrawContext *ctx,
+ const float start[3],
+ const float end[3])
+{
+ drw_shgroup_bone_relationship_lines_ex(ctx, start, end, ctx->color.wire);
+}
+
+static void drw_shgroup_bone_ik_lines(ArmatureDrawContext *ctx,
+ const float start[3],
+ const float end[3])
+{
+ float fcolor[4] = {0.8f, 0.5f, 0.0f, 1.0f}; /* add theme! */
+ drw_shgroup_bone_relationship_lines_ex(ctx, start, end, fcolor);
+}
+
+static void drw_shgroup_bone_ik_no_target_lines(ArmatureDrawContext *ctx,
+ const float start[3],
+ const float end[3])
+{
+ float fcolor[4] = {0.8f, 0.8f, 0.2f, 1.0f}; /* add theme! */
+ drw_shgroup_bone_relationship_lines_ex(ctx, start, end, fcolor);
+}
+
+static void drw_shgroup_bone_ik_spline_lines(ArmatureDrawContext *ctx,
+ const float start[3],
+ const float end[3])
+{
+ float fcolor[4] = {0.8f, 0.8f, 0.2f, 1.0f}; /* add theme! */
+ drw_shgroup_bone_relationship_lines_ex(ctx, start, end, fcolor);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing Theme Helpers
+ *
+ * Note, this section is duplicate of code in 'drawarmature.c'.
+ *
+ * \{ */
+
+/* values of colCode for set_pchan_color */
+enum {
+ PCHAN_COLOR_NORMAL = 0, /* normal drawing */
+ PCHAN_COLOR_SOLID, /* specific case where "solid" color is needed */
+ PCHAN_COLOR_CONSTS, /* "constraint" colors (which may/may-not be suppressed) */
+
+ PCHAN_COLOR_SPHEREBONE_BASE, /* for the 'stick' of sphere (envelope) bones */
+ PCHAN_COLOR_SPHEREBONE_END, /* for the ends of sphere (envelope) bones */
+ PCHAN_COLOR_LINEBONE, /* for the middle of line-bones */
+};
+
+/* This function sets the color-set for coloring a certain bone */
+static void set_pchan_colorset(ArmatureDrawContext *ctx, Object *ob, bPoseChannel *pchan)
+{
+ bPose *pose = (ob) ? ob->pose : NULL;
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bActionGroup *grp = NULL;
+ short color_index = 0;
+
+ /* sanity check */
+ if (ELEM(NULL, ob, arm, pose, pchan)) {
+ ctx->bcolor = NULL;
+ return;
+ }
+
+ /* only try to set custom color if enabled for armature */
+ if (arm->flag & ARM_COL_CUSTOM) {
+ /* currently, a bone can only use a custom color set if it's group (if it has one),
+ * has been set to use one
+ */
+ if (pchan->agrp_index) {
+ grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1));
+ if (grp) {
+ color_index = grp->customCol;
+ }
+ }
+ }
+
+ /* bcolor is a pointer to the color set to use. If NULL, then the default
+ * color set (based on the theme colors for 3d-view) is used.
+ */
+ if (color_index > 0) {
+ bTheme *btheme = UI_GetTheme();
+ ctx->bcolor = &btheme->tarm[(color_index - 1)];
+ }
+ else if (color_index == -1) {
+ /* use the group's own custom color set (grp is always != NULL here) */
+ ctx->bcolor = &grp->cs;
+ }
+ else {
+ ctx->bcolor = NULL;
+ }
+}
+
+/* This function is for brightening/darkening a given color (like UI_GetThemeColorShade3ubv()) */
+static void cp_shade_color3ub(uchar cp[3], const int offset)
+{
+ int r, g, b;
+
+ r = offset + (int)cp[0];
+ CLAMP(r, 0, 255);
+ g = offset + (int)cp[1];
+ CLAMP(g, 0, 255);
+ b = offset + (int)cp[2];
+ CLAMP(b, 0, 255);
+
+ cp[0] = r;
+ cp[1] = g;
+ cp[2] = b;
+}
+
+static void cp_shade_color3f(float cp[3], const float offset)
+{
+ add_v3_fl(cp, offset);
+ CLAMP(cp[0], 0, 255);
+ CLAMP(cp[1], 0, 255);
+ CLAMP(cp[2], 0, 255);
+}
+
+/* This function sets the gl-color for coloring a certain bone (based on bcolor) */
+static bool set_pchan_color(const ArmatureDrawContext *ctx,
+ short colCode,
+ const int boneflag,
+ const short constflag,
+ float r_color[4])
+{
+ float *fcolor = r_color;
+ const ThemeWireColor *bcolor = ctx->bcolor;
+
+ switch (colCode) {
+ case PCHAN_COLOR_NORMAL: {
+ if (bcolor) {
+ uchar cp[4] = {255};
+
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3_uchar(cp, bcolor->active);
+ if (!(boneflag & BONE_SELECTED)) {
+ cp_shade_color3ub(cp, -80);
+ }
+ }
+ else if (boneflag & BONE_SELECTED) {
+ copy_v3_v3_uchar(cp, bcolor->select);
+ }
+ else {
+ /* a bit darker than solid */
+ copy_v3_v3_uchar(cp, bcolor->solid);
+ cp_shade_color3ub(cp, -50);
+ }
+
+ rgb_uchar_to_float(fcolor, cp);
+ }
+ else {
+ if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) {
+ UI_GetThemeColor4fv(TH_BONE_POSE_ACTIVE, fcolor);
+ }
+ else if (boneflag & BONE_DRAW_ACTIVE) {
+ UI_GetThemeColorBlendShade4fv(TH_WIRE, TH_BONE_POSE, 0.15f, 0, fcolor);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ UI_GetThemeColor4fv(TH_BONE_POSE, fcolor);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_WIRE, fcolor);
+ }
+ }
+
+ return true;
+ }
+ case PCHAN_COLOR_SOLID: {
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+
+ if (bcolor) {
+ float solid_bcolor[3];
+ rgb_uchar_to_float(solid_bcolor, (uchar *)bcolor->solid);
+ interp_v3_v3v3(fcolor, fcolor, solid_bcolor, 1.0f);
+ }
+
+ return true;
+ }
+ case PCHAN_COLOR_CONSTS: {
+ if ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS)) {
+ uchar cp[4];
+ if (constflag & PCHAN_HAS_TARGET) {
+ rgba_uchar_args_set(cp, 255, 150, 0, 80);
+ }
+ else if (constflag & PCHAN_HAS_IK) {
+ rgba_uchar_args_set(cp, 255, 255, 0, 80);
+ }
+ else if (constflag & PCHAN_HAS_SPLINEIK) {
+ rgba_uchar_args_set(cp, 200, 255, 0, 80);
+ }
+ else if (constflag & PCHAN_HAS_CONST) {
+ rgba_uchar_args_set(cp, 0, 255, 120, 80);
+ }
+ else {
+ return false;
+ }
+
+ rgba_uchar_to_float(fcolor, cp);
+
+ return true;
+ }
+ return false;
+ }
+ case PCHAN_COLOR_SPHEREBONE_BASE: {
+ if (bcolor) {
+ uchar cp[4] = {255};
+
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3_uchar(cp, bcolor->active);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ copy_v3_v3_uchar(cp, bcolor->select);
+ }
+ else {
+ copy_v3_v3_uchar(cp, bcolor->solid);
+ }
+
+ rgb_uchar_to_float(fcolor, cp);
+ }
+ else {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ UI_GetThemeColorShade4fv(TH_BONE_POSE, 40, fcolor);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ UI_GetThemeColor4fv(TH_BONE_POSE, fcolor);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+ }
+ }
+
+ return true;
+ }
+ case PCHAN_COLOR_SPHEREBONE_END: {
+ if (bcolor) {
+ uchar cp[4] = {255};
+
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3_uchar(cp, bcolor->active);
+ cp_shade_color3ub(cp, 10);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ copy_v3_v3_uchar(cp, bcolor->select);
+ cp_shade_color3ub(cp, -30);
+ }
+ else {
+ copy_v3_v3_uchar(cp, bcolor->solid);
+ cp_shade_color3ub(cp, -30);
+ }
+
+ rgb_uchar_to_float(fcolor, cp);
+ }
+ else {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ UI_GetThemeColorShade4fv(TH_BONE_POSE, 10, fcolor);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ UI_GetThemeColorShade4fv(TH_BONE_POSE, -30, fcolor);
+ }
+ else {
+ UI_GetThemeColorShade4fv(TH_BONE_SOLID, -30, fcolor);
+ }
+ }
+ break;
+ }
+ case PCHAN_COLOR_LINEBONE: {
+ /* inner part in background color or constraint */
+ if ((constflag) && ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS))) {
+ uchar cp[4];
+ if (constflag & PCHAN_HAS_TARGET) {
+ rgba_uchar_args_set(cp, 255, 150, 0, 255);
+ }
+ else if (constflag & PCHAN_HAS_IK) {
+ rgba_uchar_args_set(cp, 255, 255, 0, 255);
+ }
+ else if (constflag & PCHAN_HAS_SPLINEIK) {
+ rgba_uchar_args_set(cp, 200, 255, 0, 255);
+ }
+ else if (constflag & PCHAN_HAS_CONST) {
+ rgba_uchar_args_set(cp, 0, 255, 120, 255);
+ }
+ else if (constflag) {
+ UI_GetThemeColor4ubv(TH_BONE_POSE, cp);
+ } /* PCHAN_HAS_ACTION */
+
+ rgb_uchar_to_float(fcolor, cp);
+ }
+ else {
+ if (bcolor) {
+ const uchar *cp = bcolor->solid;
+ rgb_uchar_to_float(fcolor, (uchar *)cp);
+ fcolor[3] = 204.f / 255.f;
+ }
+ else {
+ UI_GetThemeColorShade4fv(TH_BACK, -30, fcolor);
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing Color Helpers
+ * \{ */
+
+static const float *get_bone_solid_color(const ArmatureDrawContext *ctx,
+ const EditBone *UNUSED(eBone),
+ const bPoseChannel *pchan,
+ const bArmature *arm,
+ const int boneflag,
+ const short constflag)
+{
+ if (ctx->const_color) {
+ return ctx->color.bone_solid;
+ }
+
+ if (arm->flag & ARM_POSEMODE) {
+ static float disp_color[4];
+ copy_v4_v4(disp_color, pchan->draw_data->solid_color);
+ set_pchan_color(ctx, PCHAN_COLOR_SOLID, boneflag, constflag, disp_color);
+ return disp_color;
+ }
+
+ return ctx->color.bone_solid;
+}
+
+static const float *get_bone_solid_with_consts_color(const ArmatureDrawContext *ctx,
+ const EditBone *eBone,
+ const bPoseChannel *pchan,
+ const bArmature *arm,
+ const int boneflag,
+ const short constflag)
+{
+ if (ctx->const_color) {
+ return ctx->color.bone_solid;
+ }
+
+ const float *col = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+ static float consts_color[4];
+ if (set_pchan_color(ctx, PCHAN_COLOR_CONSTS, boneflag, constflag, consts_color)) {
+ interp_v3_v3v3(consts_color, col, consts_color, 0.5f);
+ }
+ else {
+ copy_v4_v4(consts_color, col);
+ }
+ return consts_color;
+}
+
+static float get_bone_wire_thickness(const ArmatureDrawContext *ctx, int boneflag)
+{
+ if (ctx->const_color) {
+ return ctx->const_wire;
+ }
+ else if (boneflag & (BONE_DRAW_ACTIVE | BONE_SELECTED)) {
+ return 2.0f;
+ }
+ else {
+ return 1.0f;
+ }
+}
+
+static const float *get_bone_wire_color(const ArmatureDrawContext *ctx,
+ const EditBone *eBone,
+ const bPoseChannel *pchan,
+ const bArmature *arm,
+ const int boneflag,
+ const short constflag)
+{
+ static float disp_color[4];
+
+ if (ctx->const_color) {
+ copy_v3_v3(disp_color, ctx->const_color);
+ }
+ else if (eBone) {
+ if (boneflag & BONE_SELECTED) {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3(disp_color, ctx->color.edge_select);
+ }
+ else {
+ copy_v3_v3(disp_color, ctx->color.bone_select);
+ }
+ }
+ else {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3(disp_color, ctx->color.bone_active_unselect);
+ }
+ else {
+ copy_v3_v3(disp_color, ctx->color.wire_edit);
+ }
+ }
+ }
+ else if (arm->flag & ARM_POSEMODE) {
+ copy_v4_v4(disp_color, pchan->draw_data->wire_color);
+ set_pchan_color(ctx, PCHAN_COLOR_NORMAL, boneflag, constflag, disp_color);
+ }
+ else {
+ copy_v3_v3(disp_color, ctx->color.vertex);
+ }
+
+ disp_color[3] = get_bone_wire_thickness(ctx, boneflag);
+
+ return disp_color;
+}
+
+#define HINT_MUL 0.5f
+#define HINT_SHADE 0.2f
+
+static void bone_hint_color_shade(float hint_color[4], const float color[4])
+{
+ mul_v3_v3fl(hint_color, color, HINT_MUL);
+ cp_shade_color3f(hint_color, -HINT_SHADE);
+ hint_color[3] = 1.0f;
+}
+
+static const float *get_bone_hint_color(const ArmatureDrawContext *ctx,
+ const EditBone *eBone,
+ const bPoseChannel *pchan,
+ const bArmature *arm,
+ const int boneflag,
+ const short constflag)
+{
+ static float hint_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ if (ctx->const_color) {
+ bone_hint_color_shade(hint_color, ctx->color.bone_solid);
+ }
+ else {
+ const float *wire_color = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ bone_hint_color_shade(hint_color, wire_color);
+ }
+
+ return hint_color;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Helper Utils
+ * \{ */
+
+static void pchan_draw_data_init(bPoseChannel *pchan)
+{
+ if (pchan->draw_data != NULL) {
+ if (pchan->draw_data->bbone_matrix_len != pchan->bone->segments) {
+ MEM_SAFE_FREE(pchan->draw_data);
+ }
+ }
+
+ if (pchan->draw_data == NULL) {
+ pchan->draw_data = MEM_mallocN(
+ sizeof(*pchan->draw_data) + sizeof(Mat4) * pchan->bone->segments, __func__);
+ pchan->draw_data->bbone_matrix_len = pchan->bone->segments;
+ }
+}
+
+static void draw_bone_update_disp_matrix_default(EditBone *eBone, bPoseChannel *pchan)
+{
+ float s[4][4], ebmat[4][4];
+ float length;
+ float(*bone_mat)[4];
+ float(*disp_mat)[4];
+ float(*disp_tail_mat)[4];
+
+ /* TODO : This should be moved to depsgraph or armature refresh
+ * and not be tight to the draw pass creation.
+ * This would refresh armature without invalidating the draw cache */
+ if (pchan) {
+ length = pchan->bone->length;
+ bone_mat = pchan->pose_mat;
+ disp_mat = pchan->disp_mat;
+ disp_tail_mat = pchan->disp_tail_mat;
+ }
+ else {
+ eBone->length = len_v3v3(eBone->tail, eBone->head);
+ ED_armature_ebone_to_mat4(eBone, ebmat);
+
+ length = eBone->length;
+ bone_mat = ebmat;
+ disp_mat = eBone->disp_mat;
+ disp_tail_mat = eBone->disp_tail_mat;
+ }
+
+ scale_m4_fl(s, length);
+ mul_m4_m4m4(disp_mat, bone_mat, s);
+ copy_m4_m4(disp_tail_mat, disp_mat);
+ translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
+}
+
+/* compute connected child pointer for B-Bone drawing */
+static void edbo_compute_bbone_child(bArmature *arm)
+{
+ EditBone *eBone;
+
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ eBone->bbone_child = NULL;
+ }
+
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
+ eBone->parent->bbone_child = eBone;
+ }
+ }
+}
+
+/* A version of BKE_pchan_bbone_spline_setup() for previewing editmode curve settings. */
+static void ebone_spline_preview(EditBone *ebone, float result_array[MAX_BBONE_SUBDIV][4][4])
+{
+ BBoneSplineParameters param;
+ EditBone *prev, *next;
+ float imat[4][4], bonemat[4][4];
+ float tmp[3];
+
+ memset(&param, 0, sizeof(param));
+
+ param.segments = ebone->segments;
+ param.length = ebone->length;
+
+ /* Get "next" and "prev" bones - these are used for handle calculations. */
+ if (ebone->bbone_prev_type == BBONE_HANDLE_AUTO) {
+ /* Use connected parent. */
+ if (ebone->flag & BONE_CONNECTED) {
+ prev = ebone->parent;
+ }
+ else {
+ prev = NULL;
+ }
+ }
+ else {
+ prev = ebone->bbone_prev;
+ }
+
+ if (ebone->bbone_next_type == BBONE_HANDLE_AUTO) {
+ /* Use connected child. */
+ next = ebone->bbone_child;
+ }
+ else {
+ next = ebone->bbone_next;
+ }
+
+ /* compute handles from connected bones */
+ if (prev || next) {
+ ED_armature_ebone_to_mat4(ebone, imat);
+ invert_m4(imat);
+
+ if (prev) {
+ param.use_prev = true;
+
+ if (ebone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
+ zero_v3(param.prev_h);
+ }
+ else if (ebone->bbone_prev_type == BBONE_HANDLE_TANGENT) {
+ sub_v3_v3v3(tmp, prev->tail, prev->head);
+ sub_v3_v3v3(tmp, ebone->head, tmp);
+ mul_v3_m4v3(param.prev_h, imat, tmp);
+ }
+ else {
+ param.prev_bbone = (prev->segments > 1);
+
+ mul_v3_m4v3(param.prev_h, imat, prev->head);
+ }
+
+ if (!param.prev_bbone) {
+ ED_armature_ebone_to_mat4(prev, bonemat);
+ mul_m4_m4m4(param.prev_mat, imat, bonemat);
+ }
+ }
+
+ if (next) {
+ param.use_next = true;
+
+ if (ebone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
+ copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0);
+ }
+ else if (ebone->bbone_next_type == BBONE_HANDLE_TANGENT) {
+ sub_v3_v3v3(tmp, next->tail, next->head);
+ add_v3_v3v3(tmp, ebone->tail, tmp);
+ mul_v3_m4v3(param.next_h, imat, tmp);
+ }
+ else {
+ param.next_bbone = (next->segments > 1);
+
+ mul_v3_m4v3(param.next_h, imat, next->tail);
+ }
+
+ ED_armature_ebone_to_mat4(next, bonemat);
+ mul_m4_m4m4(param.next_mat, imat, bonemat);
+ }
+ }
+
+ param.ease1 = ebone->ease1;
+ param.ease2 = ebone->ease2;
+ param.roll1 = ebone->roll1;
+ param.roll2 = ebone->roll2;
+
+ if (prev && (ebone->flag & BONE_ADD_PARENT_END_ROLL)) {
+ param.roll1 += prev->roll2;
+ }
+
+ param.scale_in_x = ebone->scale_in_x;
+ param.scale_in_y = ebone->scale_in_y;
+
+ param.scale_out_x = ebone->scale_out_x;
+ param.scale_out_y = ebone->scale_out_y;
+
+ param.curve_in_x = ebone->curve_in_x;
+ param.curve_in_y = ebone->curve_in_y;
+
+ param.curve_out_x = ebone->curve_out_x;
+ param.curve_out_y = ebone->curve_out_y;
+
+ ebone->segments = BKE_pchan_bbone_spline_compute(&param, false, (Mat4 *)result_array);
+}
+
+static void draw_bone_update_disp_matrix_bbone(EditBone *eBone, bPoseChannel *pchan)
+{
+ float s[4][4], ebmat[4][4];
+ float length, xwidth, zwidth;
+ float(*bone_mat)[4];
+ short bbone_segments;
+
+ /* TODO : This should be moved to depsgraph or armature refresh
+ * and not be tight to the draw pass creation.
+ * This would refresh armature without invalidating the draw cache */
+ if (pchan) {
+ length = pchan->bone->length;
+ xwidth = pchan->bone->xwidth;
+ zwidth = pchan->bone->zwidth;
+ bone_mat = pchan->pose_mat;
+ bbone_segments = pchan->bone->segments;
+ }
+ else {
+ eBone->length = len_v3v3(eBone->tail, eBone->head);
+ ED_armature_ebone_to_mat4(eBone, ebmat);
+
+ length = eBone->length;
+ xwidth = eBone->xwidth;
+ zwidth = eBone->zwidth;
+ bone_mat = ebmat;
+ bbone_segments = eBone->segments;
+ }
+
+ size_to_mat4(s, (const float[3]){xwidth, length / bbone_segments, zwidth});
+
+ /* Compute BBones segment matrices... */
+ /* Note that we need this even for one-segment bones, because box drawing need specific weirdo
+ * matrix for the box, that we cannot use to draw end points & co. */
+ if (pchan) {
+ Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
+ if (bbone_segments > 1) {
+ BKE_pchan_bbone_spline_setup(pchan, false, false, bbones_mat);
+
+ for (int i = bbone_segments; i--; bbones_mat++) {
+ mul_m4_m4m4(bbones_mat->mat, bbones_mat->mat, s);
+ mul_m4_m4m4(bbones_mat->mat, bone_mat, bbones_mat->mat);
+ }
+ }
+ else {
+ mul_m4_m4m4(bbones_mat->mat, bone_mat, s);
+ }
+ }
+ else {
+ float(*bbones_mat)[4][4] = eBone->disp_bbone_mat;
+
+ if (bbone_segments > 1) {
+ ebone_spline_preview(eBone, bbones_mat);
+
+ for (int i = bbone_segments; i--; bbones_mat++) {
+ mul_m4_m4m4(*bbones_mat, *bbones_mat, s);
+ mul_m4_m4m4(*bbones_mat, bone_mat, *bbones_mat);
+ }
+ }
+ else {
+ mul_m4_m4m4(*bbones_mat, bone_mat, s);
+ }
+ }
+
+ /* Grrr... We need default display matrix to draw end points, axes, etc. :( */
+ draw_bone_update_disp_matrix_default(eBone, pchan);
+}
+
+static void draw_bone_update_disp_matrix_custom(bPoseChannel *pchan)
+{
+ float s[4][4];
+ float length;
+ float(*bone_mat)[4];
+ float(*disp_mat)[4];
+ float(*disp_tail_mat)[4];
+
+ /* See TODO above */
+ length = PCHAN_CUSTOM_DRAW_SIZE(pchan);
+ bone_mat = pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat;
+ disp_mat = pchan->disp_mat;
+ disp_tail_mat = pchan->disp_tail_mat;
+
+ scale_m4_fl(s, length);
+ mul_m4_m4m4(disp_mat, bone_mat, s);
+ copy_m4_m4(disp_tail_mat, disp_mat);
+ translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
+}
+
+static void draw_axes(ArmatureDrawContext *ctx, EditBone *eBone, bPoseChannel *pchan)
+{
+ float final_col[4];
+ const float *col = (ctx->const_color) ?
+ ctx->const_color :
+ (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? ctx->color.text_hi :
+ ctx->color.text;
+ copy_v4_v4(final_col, col);
+ /* Mix with axes color. */
+ final_col[3] = (ctx->const_color) ? 1.0 : (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? 0.3 : 0.8;
+ drw_shgroup_bone_axes(ctx, BONE_VAR(eBone, pchan, disp_mat), final_col);
+}
+
+static void draw_points(ArmatureDrawContext *ctx,
+ const EditBone *eBone,
+ const bPoseChannel *pchan,
+ const bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ float col_solid_root[4], col_solid_tail[4], col_wire_root[4], col_wire_tail[4];
+ float col_hint_root[4], col_hint_tail[4];
+
+ copy_v4_v4(col_solid_root, ctx->color.bone_solid);
+ copy_v4_v4(col_solid_tail, ctx->color.bone_solid);
+ copy_v4_v4(col_wire_root, (ctx->const_color) ? ctx->const_color : ctx->color.vertex);
+ copy_v4_v4(col_wire_tail, (ctx->const_color) ? ctx->const_color : ctx->color.vertex);
+
+ const bool is_envelope_draw = (arm->drawtype == ARM_ENVELOPE);
+ const float envelope_ignore = -1.0f;
+
+ col_wire_tail[3] = col_wire_root[3] = get_bone_wire_thickness(ctx, boneflag);
+
+ /* Edit bone points can be selected */
+ if (eBone) {
+ if (eBone->flag & BONE_ROOTSEL) {
+ copy_v3_v3(col_wire_root, ctx->color.vertex_select);
+ }
+ if (eBone->flag & BONE_TIPSEL) {
+ copy_v3_v3(col_wire_tail, ctx->color.vertex_select);
+ }
+ }
+ else if (arm->flag & ARM_POSEMODE) {
+ const float *solid_color = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *wire_color = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ copy_v4_v4(col_wire_tail, wire_color);
+ copy_v4_v4(col_wire_root, wire_color);
+ copy_v4_v4(col_solid_tail, solid_color);
+ copy_v4_v4(col_solid_root, solid_color);
+ }
+
+ bone_hint_color_shade(col_hint_root, (ctx->const_color) ? col_solid_root : col_wire_root);
+ bone_hint_color_shade(col_hint_tail, (ctx->const_color) ? col_solid_tail : col_wire_tail);
+
+ /* Draw root point if we are not connected to our parent */
+ if (!(eBone ? (eBone->parent && (eBone->flag & BONE_CONNECTED)) :
+ (pchan->bone->parent && (pchan->bone->flag & BONE_CONNECTED)))) {
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_ROOT);
+ }
+
+ if (eBone) {
+ if (is_envelope_draw) {
+ drw_shgroup_bone_envelope(ctx,
+ eBone->disp_mat,
+ col_solid_root,
+ col_hint_root,
+ col_wire_root,
+ &eBone->rad_head,
+ &envelope_ignore);
+ }
+ else {
+ drw_shgroup_bone_point(ctx, eBone->disp_mat, col_solid_root, col_hint_root, col_wire_root);
+ }
+ }
+ else {
+ Bone *bone = pchan->bone;
+ if (is_envelope_draw) {
+ drw_shgroup_bone_envelope(ctx,
+ pchan->disp_mat,
+ col_solid_root,
+ col_hint_root,
+ col_wire_root,
+ &bone->rad_head,
+ &envelope_ignore);
+ }
+ else {
+ drw_shgroup_bone_point(ctx, pchan->disp_mat, col_solid_root, col_hint_root, col_wire_root);
+ }
+ }
+ }
+
+ /* Draw tip point */
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_TIP);
+ }
+
+ if (is_envelope_draw) {
+ const float *rad_tail = eBone ? &eBone->rad_tail : &pchan->bone->rad_tail;
+ drw_shgroup_bone_envelope(ctx,
+ BONE_VAR(eBone, pchan, disp_mat),
+ col_solid_tail,
+ col_hint_tail,
+ col_wire_tail,
+ &envelope_ignore,
+ rad_tail);
+ }
+ else {
+ drw_shgroup_bone_point(
+ ctx, BONE_VAR(eBone, pchan, disp_tail_mat), col_solid_tail, col_hint_tail, col_wire_tail);
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Bones
+ * \{ */
+
+static void draw_bone_custom_shape(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ const float *col_solid = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_hint = get_bone_hint_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float(*disp_mat)[4] = pchan->disp_mat;
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ if (pchan->custom->type == OB_EMPTY) {
+ Object *ob = pchan->custom;
+ if (ob->empty_drawtype != OB_EMPTY_IMAGE) {
+ drw_shgroup_bone_custom_empty(ctx, disp_mat, col_wire, pchan->custom);
+ }
+ }
+ if ((boneflag & BONE_DRAWWIRE) == 0) {
+ drw_shgroup_bone_custom_solid(ctx, disp_mat, col_solid, col_hint, col_wire, pchan->custom);
+ }
+ else {
+ drw_shgroup_bone_custom_wire(ctx, disp_mat, col_wire, pchan->custom);
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+}
+
+static void draw_bone_envelope(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ const float *col_solid = get_bone_solid_with_consts_color(
+ ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_hint = get_bone_hint_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+ float *rad_head, *rad_tail, *distance;
+ if (eBone) {
+ rad_tail = &eBone->rad_tail;
+ distance = &eBone->dist;
+ rad_head = (eBone->parent && (boneflag & BONE_CONNECTED)) ? &eBone->parent->rad_tail :
+ &eBone->rad_head;
+ }
+ else {
+ rad_tail = &pchan->bone->rad_tail;
+ distance = &pchan->bone->dist;
+ rad_head = (pchan->parent && (boneflag & BONE_CONNECTED)) ? &pchan->parent->bone->rad_tail :
+ &pchan->bone->rad_head;
+ }
+
+ if ((select_id == -1) && (boneflag & BONE_NO_DEFORM) == 0 &&
+ ((boneflag & BONE_SELECTED) || (eBone && (boneflag & (BONE_ROOTSEL | BONE_TIPSEL))))) {
+ drw_shgroup_bone_envelope_distance(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), rad_head, rad_tail, distance);
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ drw_shgroup_bone_envelope(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), col_solid, col_hint, col_wire, rad_head, rad_tail);
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ draw_points(ctx, eBone, pchan, arm, boneflag, constflag, select_id);
+}
+
+static void draw_bone_line(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ const float *col_bone = get_bone_solid_with_consts_color(
+ ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float no_display[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float *col_head = no_display;
+ const float *col_tail = col_bone;
+
+ if (ctx->const_color != NULL) {
+ col_wire = no_display; /* actually shrink the display. */
+ col_bone = col_head = col_tail = ctx->const_color;
+ }
+ else {
+ if (eBone) {
+ if (eBone->flag & BONE_TIPSEL) {
+ col_tail = ctx->color.vertex_select;
+ }
+ if (boneflag & BONE_SELECTED) {
+ col_bone = ctx->color.edge_select;
+ }
+ col_wire = ctx->color.wire;
+ }
+
+ /* Draw root point if we are not connected to our parent. */
+ if (!(eBone ? (eBone->parent && (eBone->flag & BONE_CONNECTED)) :
+ (pchan->bone->parent && (pchan->bone->flag & BONE_CONNECTED)))) {
+
+ if (eBone) {
+ col_head = (eBone->flag & BONE_ROOTSEL) ? ctx->color.vertex_select : col_bone;
+ }
+ else {
+ col_head = col_bone;
+ }
+ }
+ }
+
+ if (select_id == -1) {
+ /* Not in selection mode, draw everything at once. */
+ drw_shgroup_bone_stick(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), col_wire, col_bone, col_head, col_tail);
+ }
+ else {
+ /* In selection mode, draw bone, root and tip separately. */
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ drw_shgroup_bone_stick(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), col_wire, col_bone, no_display, no_display);
+
+ if (col_head[3] > 0.0f) {
+ DRW_select_load_id(select_id | BONESEL_ROOT);
+ drw_shgroup_bone_stick(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), col_wire, no_display, col_head, no_display);
+ }
+
+ DRW_select_load_id(select_id | BONESEL_TIP);
+ drw_shgroup_bone_stick(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), col_wire, no_display, no_display, col_tail);
+
+ DRW_select_load_id(-1);
+ }
+}
+
+static void draw_bone_wire(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ if (pchan) {
+ Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
+ BLI_assert(bbones_mat != NULL);
+
+ for (int i = pchan->bone->segments; i--; bbones_mat++) {
+ drw_shgroup_bone_wire(ctx, bbones_mat->mat, col_wire);
+ }
+ }
+ else if (eBone) {
+ for (int i = 0; i < eBone->segments; i++) {
+ drw_shgroup_bone_wire(ctx, eBone->disp_bbone_mat[i], col_wire);
+ }
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ if (eBone) {
+ draw_points(ctx, eBone, pchan, arm, boneflag, constflag, select_id);
+ }
+}
+
+static void draw_bone_box(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ const float *col_solid = get_bone_solid_with_consts_color(
+ ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_hint = get_bone_hint_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ if (pchan) {
+ Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
+ BLI_assert(bbones_mat != NULL);
+
+ for (int i = pchan->bone->segments; i--; bbones_mat++) {
+ drw_shgroup_bone_box(ctx, bbones_mat->mat, col_solid, col_hint, col_wire);
+ }
+ }
+ else if (eBone) {
+ for (int i = 0; i < eBone->segments; i++) {
+ drw_shgroup_bone_box(ctx, eBone->disp_bbone_mat[i], col_solid, col_hint, col_wire);
+ }
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ if (eBone) {
+ draw_points(ctx, eBone, pchan, arm, boneflag, constflag, select_id);
+ }
+}
+
+static void draw_bone_octahedral(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag,
+ const int select_id)
+{
+ const float *col_solid = get_bone_solid_with_consts_color(
+ ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+ const float *col_hint = get_bone_hint_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ drw_shgroup_bone_octahedral(
+ ctx, BONE_VAR(eBone, pchan, disp_mat), col_solid, col_hint, col_wire);
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ draw_points(ctx, eBone, pchan, arm, boneflag, constflag, select_id);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Degrees of Freedom
+ * \{ */
+
+static void draw_bone_degrees_of_freedom(ArmatureDrawContext *ctx, bPoseChannel *pchan)
+{
+ BoneInstanceData inst_data;
+ float tmp[4][4], posetrans[4][4];
+ float xminmax[2], zminmax[2];
+ float color[4];
+
+ if (ctx->dof_sphere == NULL) {
+ return;
+ }
+
+ /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */
+ xminmax[0] = sinf(pchan->limitmin[0] * 0.5f);
+ xminmax[1] = sinf(pchan->limitmax[0] * 0.5f);
+ zminmax[0] = sinf(pchan->limitmin[2] * 0.5f);
+ zminmax[1] = sinf(pchan->limitmax[2] * 0.5f);
+
+ unit_m4(posetrans);
+ translate_m4(posetrans, pchan->pose_mat[3][0], pchan->pose_mat[3][1], pchan->pose_mat[3][2]);
+ /* in parent-bone pose space... */
+ if (pchan->parent) {
+ copy_m4_m4(tmp, pchan->parent->pose_mat);
+ zero_v3(tmp[3]);
+ mul_m4_m4m4(posetrans, posetrans, tmp);
+ }
+ /* ... but own restspace */
+ mul_m4_m4m3(posetrans, posetrans, pchan->bone->bone_mat);
+
+ float scale = pchan->bone->length * pchan->size[1];
+ scale_m4_fl(tmp, scale);
+ tmp[1][1] = -tmp[1][1];
+ mul_m4_m4m4(posetrans, posetrans, tmp);
+
+ /* into world space. */
+ mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, posetrans);
+
+ if ((pchan->ikflag & BONE_IK_XLIMIT) && (pchan->ikflag & BONE_IK_ZLIMIT)) {
+ bone_instance_data_set_angle_minmax(
+ &inst_data, xminmax[0], zminmax[0], xminmax[1], zminmax[1]);
+
+ copy_v4_fl4(color, 0.25f, 0.25f, 0.25f, 0.25f);
+ DRW_buffer_add_entry(ctx->dof_sphere, color, &inst_data);
+
+ copy_v4_fl4(color, 0.0f, 0.0f, 0.0f, 1.0f);
+ DRW_buffer_add_entry(ctx->dof_lines, color, &inst_data);
+ }
+ if (pchan->ikflag & BONE_IK_XLIMIT) {
+ bone_instance_data_set_angle_minmax(&inst_data, xminmax[0], 0.0f, xminmax[1], 0.0f);
+ copy_v4_fl4(color, 1.0f, 0.0f, 0.0f, 1.0f);
+ DRW_buffer_add_entry(ctx->dof_lines, color, &inst_data);
+ }
+ if (pchan->ikflag & BONE_IK_ZLIMIT) {
+ bone_instance_data_set_angle_minmax(&inst_data, 0.0f, zminmax[0], 0.0f, zminmax[1]);
+ copy_v4_fl4(color, 0.0f, 0.0f, 1.0f, 1.0f);
+ DRW_buffer_add_entry(ctx->dof_lines, color, &inst_data);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Relationships
+ * \{ */
+
+static void pchan_draw_ik_lines(ArmatureDrawContext *ctx,
+ bPoseChannel *pchan,
+ const bool only_temp,
+ const int constflag)
+{
+ bConstraint *con;
+ bPoseChannel *parchan;
+ float *line_start = NULL, *line_end = NULL;
+
+ for (con = pchan->constraints.first; con; con = con->next) {
+ if (con->enforce == 0.0f) {
+ continue;
+ }
+
+ switch (con->type) {
+ case CONSTRAINT_TYPE_KINEMATIC: {
+ bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+ int segcount = 0;
+
+ /* if only_temp, only draw if it is a temporary ik-chain */
+ if (only_temp && !(data->flag & CONSTRAINT_IK_TEMP)) {
+ continue;
+ }
+
+ /* exclude tip from chain? */
+ parchan = ((data->flag & CONSTRAINT_IK_TIP) == 0) ? pchan->parent : pchan;
+ line_start = parchan->pose_tail;
+
+ /* Find the chain's root */
+ while (parchan->parent) {
+ segcount++;
+ if (segcount == data->rootbone || segcount > 255) {
+ break; /* 255 is weak */
+ }
+ parchan = parchan->parent;
+ }
+
+ if (parchan) {
+ line_end = parchan->pose_head;
+
+ if (constflag & PCHAN_HAS_TARGET) {
+ drw_shgroup_bone_ik_lines(ctx, line_start, line_end);
+ }
+ else {
+ drw_shgroup_bone_ik_no_target_lines(ctx, line_start, line_end);
+ }
+ }
+ break;
+ }
+ case CONSTRAINT_TYPE_SPLINEIK: {
+ bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+ int segcount = 0;
+
+ /* don't draw if only_temp, as Spline IK chains cannot be temporary */
+ if (only_temp) {
+ continue;
+ }
+
+ parchan = pchan;
+ line_start = parchan->pose_tail;
+
+ /* Find the chain's root */
+ while (parchan->parent) {
+ segcount++;
+ /* FIXME: revise the breaking conditions */
+ if (segcount == data->chainlen || segcount > 255) {
+ break; /* 255 is weak */
+ }
+ parchan = parchan->parent;
+ }
+ /* Only draw line in case our chain is more than one bone long! */
+ if (parchan != pchan) { /* XXX revise the breaking conditions to only stop at the tail? */
+ line_end = parchan->pose_head;
+ drw_shgroup_bone_ik_spline_lines(ctx, line_start, line_end);
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void draw_bone_relations(ArmatureDrawContext *ctx,
+ EditBone *ebone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag,
+ const short constflag)
+{
+ if (ebone && ebone->parent) {
+ if (ctx->do_relations) {
+ /* Always draw for unconnected bones, regardless of selection,
+ * since riggers will want to know about the links between bones
+ */
+ if ((boneflag & BONE_CONNECTED) == 0) {
+ drw_shgroup_bone_relationship_lines(ctx, ebone->head, ebone->parent->tail);
+ }
+ }
+ }
+ else if (pchan && pchan->parent) {
+ if (ctx->do_relations) {
+ /* Only draw if bone or its parent is selected - reduces viewport complexity with complex
+ * rigs */
+ if ((boneflag & BONE_SELECTED) ||
+ (pchan->parent->bone && (pchan->parent->bone->flag & BONE_SELECTED))) {
+ if ((boneflag & BONE_CONNECTED) == 0) {
+ drw_shgroup_bone_relationship_lines(ctx, pchan->pose_head, pchan->parent->pose_tail);
+ }
+ }
+ }
+
+ /* Draw a line to IK root bone if bone is selected. */
+ if (arm->flag & ARM_POSEMODE) {
+ if (constflag & (PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK)) {
+ if (boneflag & BONE_SELECTED) {
+ pchan_draw_ik_lines(ctx, pchan, !ctx->do_relations, constflag);
+ }
+ }
+ }
+ }
+}
+
+static void draw_bone_name(ArmatureDrawContext *ctx,
+ EditBone *eBone,
+ bPoseChannel *pchan,
+ bArmature *arm,
+ const int boneflag)
+{
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ uchar color[4];
+ float vec[3];
+
+ bool highlight = (pchan && (arm->flag & ARM_POSEMODE) && (boneflag & BONE_SELECTED)) ||
+ (eBone && (eBone->flag & BONE_SELECTED));
+
+ UI_GetThemeColor4ubv(highlight ? TH_TEXT_HI : TH_TEXT, color);
+
+ float *head = pchan ? pchan->pose_head : eBone->head;
+ float *tail = pchan ? pchan->pose_tail : eBone->tail;
+ mid_v3_v3v3(vec, head, tail);
+ mul_m4_v3(ctx->ob->obmat, vec);
+
+ DRW_text_cache_add(dt,
+ vec,
+ (pchan) ? pchan->name : eBone->name,
+ (pchan) ? strlen(pchan->name) : strlen(eBone->name),
+ 10,
+ 0,
+ DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+ color);
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Main Draw Loops
+ * \{ */
+
+static void draw_armature_edit(ArmatureDrawContext *ctx)
+{
+ Object *ob = ctx->ob;
+ EditBone *eBone;
+ int index;
+ const bool is_select = DRW_state_is_select();
+ const bool show_text = DRW_state_show_text();
+
+ const Object *ob_orig = DEG_get_original_object(ob);
+ /* FIXME(campbell): We should be able to use the CoW object,
+ * however the active bone isn't updated. Long term solution is an 'EditArmature' struct.
+ * for now we can draw from the original armature. See: T66773. */
+ // bArmature *arm = ob->data;
+ bArmature *arm = ob_orig->data;
+
+ edbo_compute_bbone_child(arm);
+
+ for (eBone = arm->edbo->first, index = ob_orig->runtime.select_id; eBone;
+ eBone = eBone->next, index += 0x10000) {
+ if (eBone->layer & arm->layer) {
+ if ((eBone->flag & BONE_HIDDEN_A) == 0) {
+ const int select_id = is_select ? index : (uint)-1;
+ const short constflag = 0;
+
+ /* catch exception for bone with hidden parent */
+ int boneflag = eBone->flag;
+ if ((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent)) {
+ boneflag &= ~BONE_CONNECTED;
+ }
+
+ /* set temporary flag for drawing bone as active, but only if selected */
+ if (eBone == arm->act_edbone) {
+ boneflag |= BONE_DRAW_ACTIVE;
+ }
+
+ draw_bone_relations(ctx, eBone, NULL, arm, boneflag, constflag);
+
+ if (arm->drawtype == ARM_ENVELOPE) {
+ draw_bone_update_disp_matrix_default(eBone, NULL);
+ draw_bone_envelope(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_LINE) {
+ draw_bone_update_disp_matrix_default(eBone, NULL);
+ draw_bone_line(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_WIRE) {
+ draw_bone_update_disp_matrix_bbone(eBone, NULL);
+ draw_bone_wire(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_B_BONE) {
+ draw_bone_update_disp_matrix_bbone(eBone, NULL);
+ draw_bone_box(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+ else {
+ draw_bone_update_disp_matrix_default(eBone, NULL);
+ draw_bone_octahedral(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+
+ if (show_text && (arm->flag & ARM_DRAWNAMES)) {
+ draw_bone_name(ctx, eBone, NULL, arm, boneflag);
+ }
+
+ if (arm->flag & ARM_DRAWAXES) {
+ draw_axes(ctx, eBone, NULL);
+ }
+ }
+ }
+ }
+}
+
+static void draw_armature_pose(ArmatureDrawContext *ctx)
+{
+ Object *ob = ctx->ob;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan;
+ int index = -1;
+ const bool show_text = DRW_state_show_text();
+
+ /* We can't safely draw non-updated pose, might contain NULL bone pointers... */
+ if (ob->pose->flag & POSE_RECALC) {
+ return;
+ }
+
+ bool is_pose_select = false;
+ /* Object can be edited in the scene. */
+ if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
+ if ((draw_ctx->object_mode & OB_MODE_POSE) || (ob == draw_ctx->object_pose)) {
+ arm->flag |= ARM_POSEMODE;
+ }
+ is_pose_select =
+ /* If we're in pose-mode or object-mode with the ability to enter pose mode. */
+ (
+ /* Draw as if in pose mode (when selection is possible). */
+ (arm->flag & ARM_POSEMODE) ||
+ /* When we're in object mode, which may select bones. */
+ ((ob->mode & OB_MODE_POSE) &&
+ (
+ /* Switch from object mode when object lock is disabled. */
+ ((draw_ctx->object_mode == OB_MODE_OBJECT) &&
+ (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) ||
+ /* Allow selection when in weight-paint mode
+ * (selection code ensures this wont become active). */
+ ((draw_ctx->object_mode == OB_MODE_WEIGHT_PAINT) &&
+ (draw_ctx->object_pose != NULL))))) &&
+ DRW_state_is_select();
+
+ if (is_pose_select) {
+ const Object *ob_orig = DEG_get_original_object(ob);
+ index = ob_orig->runtime.select_id;
+ }
+ }
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, index += 0x10000) {
+ Bone *bone = pchan->bone;
+ const bool bone_visible = (bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0;
+
+ if (bone_visible) {
+ if (bone->layer & arm->layer) {
+ const bool draw_dofs = !is_pose_select && ctx->show_relations &&
+ (arm->flag & ARM_POSEMODE) && (bone->flag & BONE_SELECTED) &&
+ ((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
+ (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_ZLIMIT));
+ const int select_id = is_pose_select ? index : (uint)-1;
+ const short constflag = pchan->constflag;
+
+ pchan_draw_data_init(pchan);
+
+ if (!ctx->const_color) {
+ set_pchan_colorset(ctx, ob, pchan);
+ }
+
+ int boneflag = bone->flag;
+ /* catch exception for bone with hidden parent */
+ boneflag = bone->flag;
+ if ((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
+ boneflag &= ~BONE_CONNECTED;
+ }
+
+ /* set temporary flag for drawing bone as active, but only if selected */
+ if (bone == arm->act_bone) {
+ boneflag |= BONE_DRAW_ACTIVE;
+ }
+
+ draw_bone_relations(ctx, NULL, pchan, arm, boneflag, constflag);
+
+ if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) {
+ draw_bone_update_disp_matrix_custom(pchan);
+ draw_bone_custom_shape(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_ENVELOPE) {
+ draw_bone_update_disp_matrix_default(NULL, pchan);
+ draw_bone_envelope(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_LINE) {
+ draw_bone_update_disp_matrix_default(NULL, pchan);
+ draw_bone_line(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_WIRE) {
+ draw_bone_update_disp_matrix_bbone(NULL, pchan);
+ draw_bone_wire(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_B_BONE) {
+ draw_bone_update_disp_matrix_bbone(NULL, pchan);
+ draw_bone_box(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else {
+ draw_bone_update_disp_matrix_default(NULL, pchan);
+ draw_bone_octahedral(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+
+ if (draw_dofs) {
+ draw_bone_degrees_of_freedom(ctx, pchan);
+ }
+
+ if (show_text && (arm->flag & ARM_DRAWNAMES)) {
+ draw_bone_name(ctx, NULL, pchan, arm, boneflag);
+ }
+
+ if (arm->flag & ARM_DRAWAXES) {
+ draw_axes(ctx, NULL, pchan);
+ }
+ }
+ }
+ }
+
+ arm->flag &= ~ARM_POSEMODE;
+}
+
+static void armature_context_setup(ArmatureDrawContext *ctx,
+ OVERLAY_PrivateData *pd,
+ Object *ob,
+ const bool do_envelope_dist,
+ const bool is_pose_mode,
+ float *const_color)
+{
+ const bool is_xray = (ob->dtx & OB_DRAWXRAY) != 0 ||
+ (pd->armature.do_pose_fade_geom && is_pose_mode);
+ const bool is_filled = !pd->armature.transparent || do_envelope_dist;
+ bArmature *arm = ob->data;
+ OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[is_xray];
+
+ switch (arm->drawtype) {
+ case ARM_ENVELOPE:
+ ctx->envelope_outline = cb->envelope_outline;
+ ctx->envelope_solid = (is_filled) ? cb->envelope_solid : NULL;
+ ctx->envelope_distance = (do_envelope_dist) ? cb->envelope_distance : NULL;
+ break;
+ case ARM_LINE:
+ ctx->stick = cb->stick;
+ break;
+ case ARM_WIRE:
+ ctx->wire = cb->wire;
+ break;
+ case ARM_B_BONE:
+ ctx->outline = cb->box_outline;
+ ctx->solid = (is_filled) ? cb->box_solid : NULL;
+ break;
+ case ARM_OCTA:
+ ctx->outline = cb->octa_outline;
+ ctx->solid = (is_filled) ? cb->octa_solid : NULL;
+ break;
+ }
+ ctx->ob = ob;
+ ctx->extras = &pd->extra_call_buffers[is_xray];
+ ctx->dof_lines = cb->dof_lines;
+ ctx->dof_sphere = cb->dof_sphere;
+ ctx->point_solid = (is_filled) ? cb->point_solid : NULL;
+ ctx->point_outline = cb->point_outline;
+ ctx->custom_solid = (is_filled) ? cb->custom_solid : NULL;
+ ctx->custom_outline = cb->custom_outline;
+ ctx->custom_wire = cb->custom_solid; /* Use same shader. */
+ ctx->custom_shapes_ghash = cb->custom_shapes_ghash;
+ ctx->transparent = pd->armature.transparent;
+ ctx->show_relations = pd->armature.show_relations;
+ ctx->const_color = const_color;
+ ctx->const_wire = (((ob->base_flag & BASE_SELECTED) || (arm->drawtype == ARM_WIRE)) ?
+ 1.5f :
+ ((ctx->transparent) ? 1.0f : 0.0f));
+
+ /** See: 'set_pchan_color'*/
+#define NO_ALPHA(c) (((c)[3] = 1.0f), (c))
+
+ UI_GetThemeColor3fv(TH_SELECT, NO_ALPHA(ctx->color.select));
+ UI_GetThemeColorShade3fv(TH_EDGE_SELECT, 60, NO_ALPHA(ctx->color.edge_select));
+ UI_GetThemeColorShade3fv(TH_EDGE_SELECT, -20, NO_ALPHA(ctx->color.bone_select));
+ UI_GetThemeColor3fv(TH_WIRE, NO_ALPHA(ctx->color.wire));
+ UI_GetThemeColor3fv(TH_WIRE_EDIT, NO_ALPHA(ctx->color.wire_edit));
+ UI_GetThemeColor3fv(TH_BONE_SOLID, NO_ALPHA(ctx->color.bone_solid));
+ UI_GetThemeColorBlendShade3fv(
+ TH_WIRE_EDIT, TH_EDGE_SELECT, 0.15f, 0, NO_ALPHA(ctx->color.bone_active_unselect));
+ UI_GetThemeColor3fv(TH_BONE_POSE, NO_ALPHA(ctx->color.bone_pose));
+ UI_GetThemeColor3fv(TH_BONE_POSE_ACTIVE, NO_ALPHA(ctx->color.bone_pose_active));
+ UI_GetThemeColorBlendShade3fv(
+ TH_WIRE, TH_BONE_POSE, 0.15f, 0, NO_ALPHA(ctx->color.bone_pose_active_unselect));
+ UI_GetThemeColor3fv(TH_TEXT_HI, NO_ALPHA(ctx->color.text_hi));
+ UI_GetThemeColor3fv(TH_TEXT, NO_ALPHA(ctx->color.text));
+ UI_GetThemeColor3fv(TH_VERTEX_SELECT, NO_ALPHA(ctx->color.vertex_select));
+ UI_GetThemeColor3fv(TH_VERTEX, NO_ALPHA(ctx->color.vertex));
+
+#undef NO_ALPHA
+}
+
+void OVERLAY_edit_armature_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ ArmatureDrawContext arm_ctx;
+ armature_context_setup(&arm_ctx, pd, ob, true, false, NULL);
+ draw_armature_edit(&arm_ctx);
+}
+
+void OVERLAY_pose_armature_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ ArmatureDrawContext arm_ctx;
+ armature_context_setup(&arm_ctx, pd, ob, true, true, NULL);
+ draw_armature_pose(&arm_ctx);
+}
+
+void OVERLAY_armature_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ ArmatureDrawContext arm_ctx;
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+ armature_context_setup(&arm_ctx, pd, ob, false, false, color);
+ draw_armature_pose(&arm_ctx);
+}
+
+static bool POSE_is_driven_by_active_armature(Object *ob)
+{
+ Object *ob_arm = modifiers_isDeformedByArmature(ob);
+ if (ob_arm) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ bool is_active = OVERLAY_armature_is_pose_mode(ob_arm, draw_ctx);
+ if (!is_active && ob_arm->proxy_from) {
+ is_active = OVERLAY_armature_is_pose_mode(ob_arm->proxy_from, draw_ctx);
+ }
+ return is_active;
+ }
+ else {
+ Object *ob_mesh_deform = modifiers_isDeformedByMeshDeform(ob);
+ if (ob_mesh_deform) {
+ /* Recursive. */
+ return POSE_is_driven_by_active_armature(ob_mesh_deform);
+ }
+ }
+ return false;
+}
+
+void OVERLAY_pose_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ if (POSE_is_driven_by_active_armature(ob)) {
+ DRW_shgroup_call(pd->armature_bone_select_act_grp, geom, ob);
+ }
+ else {
+ DRW_shgroup_call(pd->armature_bone_select_grp, geom, ob);
+ }
+ }
+}
+
+void OVERLAY_armature_cache_finish(OVERLAY_Data *vedata)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ for (int i = 0; i < 2; i++) {
+ if (pd->armature_call_buffers[i].custom_shapes_ghash) {
+ /* TODO(fclem): Do not free it for each frame but reuse it. Avoiding alloc cost. */
+ BLI_ghash_free(pd->armature_call_buffers[i].custom_shapes_ghash, NULL, NULL);
+ }
+ }
+}
+
+void OVERLAY_armature_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->armature_transp_ps);
+ DRW_draw_pass(psl->armature_ps[0]);
+}
+
+void OVERLAY_armature_in_front_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ if (psl->armature_bone_select_ps == NULL) {
+ DRW_draw_pass(psl->armature_ps[1]);
+ }
+}
+
+void OVERLAY_pose_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (psl->armature_bone_select_ps != NULL) {
+ DRW_draw_pass(psl->armature_bone_select_ps);
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
+ }
+ /* Selection still works because we are drawing only the pose bones in this case. */
+
+ DRW_draw_pass(psl->armature_ps[1]);
+ }
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/overlay_edit_curve.c b/source/blender/draw/engines/overlay/overlay_edit_curve.c
new file mode 100644
index 00000000000..81253347632
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_edit_curve.c
@@ -0,0 +1,127 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_curve_types.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_edit_curve_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ DRWShadingGroup *grp;
+ GPUShader *sh;
+ DRWState state;
+
+ pd->edit_curve.show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
+ pd->shdata.edit_curve_normal_length = v3d->overlay.normals_length;
+
+ /* Run Twice for in-front passes. */
+ for (int i = 0; i < 2; i++) {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH;
+ state |= ((i == 0) ? DRW_STATE_DEPTH_LESS_EQUAL : DRW_STATE_DEPTH_ALWAYS);
+ DRW_PASS_CREATE(psl->edit_curve_wire_ps[i], state | pd->clipping_state);
+
+ sh = OVERLAY_shader_edit_curve_wire();
+ pd->edit_curve_normal_grp[i] = grp = DRW_shgroup_create(sh, psl->edit_curve_wire_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "normalSize", pd->shdata.edit_curve_normal_length);
+
+ pd->edit_curve_wire_grp[i] = grp = DRW_shgroup_create(sh, psl->edit_curve_wire_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "normalSize", 0.0f);
+ }
+ {
+ state = DRW_STATE_WRITE_COLOR;
+ DRW_PASS_CREATE(psl->edit_curve_handle_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_edit_curve_handle();
+ pd->edit_curve_handle_grp = grp = DRW_shgroup_create(sh, psl->edit_curve_handle_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "showCurveHandles", pd->edit_curve.show_handles);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+ sh = OVERLAY_shader_edit_curve_point();
+ pd->edit_curve_points_grp = grp = DRW_shgroup_create(sh, psl->edit_curve_handle_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ }
+}
+
+void OVERLAY_edit_curve_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ bool draw_normals = (pd->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_NORMALS) != 0;
+ bool do_xray = (ob->dtx & OB_DRAWXRAY) != 0;
+
+ Curve *cu = ob->data;
+ struct GPUBatch *geom;
+
+ geom = DRW_cache_curve_edge_wire_get(ob);
+ if (geom) {
+ DRW_shgroup_call_no_cull(pd->edit_curve_wire_grp[do_xray], geom, ob);
+ }
+
+ if ((cu->flag & CU_3D) && draw_normals) {
+ geom = DRW_cache_curve_edge_normal_get(ob);
+ DRW_shgroup_call_instances(pd->edit_curve_normal_grp[do_xray], ob, geom, 3);
+ }
+
+ geom = DRW_cache_curve_edge_overlay_get(ob);
+ if (geom) {
+ DRW_shgroup_call_no_cull(pd->edit_curve_handle_grp, geom, ob);
+ }
+
+ geom = DRW_cache_curve_vert_overlay_get(ob, pd->edit_curve.show_handles);
+ if (geom) {
+ DRW_shgroup_call_no_cull(pd->edit_curve_points_grp, geom, ob);
+ }
+}
+
+void OVERLAY_edit_surf_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUBatch *geom;
+
+ geom = DRW_cache_curve_edge_overlay_get(ob);
+ if (geom) {
+ DRW_shgroup_call_no_cull(pd->edit_curve_handle_grp, geom, ob);
+ }
+
+ geom = DRW_cache_curve_vert_overlay_get(ob, false);
+ if (geom) {
+ DRW_shgroup_call_no_cull(pd->edit_curve_points_grp, geom, ob);
+ }
+}
+
+void OVERLAY_edit_curve_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->edit_curve_wire_ps[0]);
+ DRW_draw_pass(psl->edit_curve_wire_ps[1]);
+
+ DRW_draw_pass(psl->edit_curve_handle_ps);
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
new file mode 100644
index 00000000000..e03ed7f2d00
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
@@ -0,0 +1,419 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "ED_view3d.h"
+
+#include "DNA_mesh_types.h"
+
+#include "BKE_editmesh.h"
+
+#include "draw_cache_impl.h"
+#include "draw_manager_text.h"
+
+#include "overlay_private.h"
+
+#define OVERLAY_EDIT_TEXT \
+ (V3D_OVERLAY_EDIT_EDGE_LEN | V3D_OVERLAY_EDIT_FACE_AREA | V3D_OVERLAY_EDIT_FACE_ANG | \
+ V3D_OVERLAY_EDIT_EDGE_ANG | V3D_OVERLAY_EDIT_INDICES)
+
+void OVERLAY_edit_mesh_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ pd->edit_mesh.do_zbufclip = XRAY_FLAG_ENABLED(draw_ctx->v3d);
+
+ if (!pd->edit_mesh.do_zbufclip) {
+ /* Small texture which will have very small impact on rendertime. */
+ DRW_texture_ensure_2d(&txl->dummy_depth_tx, 1, 1, GPU_DEPTH_COMPONENT24, 0);
+ }
+
+ /* Create view with depth offset */
+ DRWView *default_view = (DRWView *)DRW_view_default_get();
+ /* Don't use AA view (pd->view_default) because edit mode already has anti-aliasing. */
+ pd->view_edit_faces = default_view;
+ pd->view_edit_faces_cage = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 0.5f);
+ pd->view_edit_edges = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 1.0f);
+ pd->view_edit_verts = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 1.5f);
+}
+
+void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ OVERLAY_ShadingData *shdata = &pd->shdata;
+ DRWShadingGroup *grp = NULL;
+ GPUShader *sh = NULL;
+ DRWState state = 0;
+
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ToolSettings *tsettings = draw_ctx->scene->toolsettings;
+ View3D *v3d = draw_ctx->v3d;
+ bool select_vert = pd->edit_mesh.select_vert = (tsettings->selectmode & SCE_SELECT_VERTEX) != 0;
+ bool select_face = pd->edit_mesh.select_face = (tsettings->selectmode & SCE_SELECT_FACE) != 0;
+ bool select_edge = pd->edit_mesh.select_edge = (tsettings->selectmode & SCE_SELECT_EDGE) != 0;
+
+ bool do_occlude_wire = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 0;
+ bool show_face_dots = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) != 0 ||
+ pd->edit_mesh.do_zbufclip;
+
+ pd->edit_mesh.ghost_ob = 0;
+ pd->edit_mesh.edit_ob = 0;
+ pd->edit_mesh.do_faces = true;
+ pd->edit_mesh.do_edges = true;
+
+ int *mask = shdata->data_mask;
+ mask[0] = 0xFF; /* Face Flag */
+ mask[1] = 0xFF; /* Edge Flag */
+
+ const int flag = pd->edit_mesh.flag = v3d->overlay.edit_flag;
+
+ SET_FLAG_FROM_TEST(mask[0], flag & V3D_OVERLAY_EDIT_FACES, VFLAG_FACE_SELECTED);
+ SET_FLAG_FROM_TEST(mask[0], flag & V3D_OVERLAY_EDIT_FREESTYLE_FACE, VFLAG_FACE_FREESTYLE);
+ SET_FLAG_FROM_TEST(mask[1], flag & V3D_OVERLAY_EDIT_FREESTYLE_EDGE, VFLAG_EDGE_FREESTYLE);
+ SET_FLAG_FROM_TEST(mask[1], flag & V3D_OVERLAY_EDIT_SEAMS, VFLAG_EDGE_SEAM);
+ SET_FLAG_FROM_TEST(mask[1], flag & V3D_OVERLAY_EDIT_SHARP, VFLAG_EDGE_SHARP);
+ SET_FLAG_FROM_TEST(mask[2], flag & V3D_OVERLAY_EDIT_CREASES, 0xFF);
+ SET_FLAG_FROM_TEST(mask[3], flag & V3D_OVERLAY_EDIT_BWEIGHTS, 0xFF);
+
+ if ((flag & V3D_OVERLAY_EDIT_FACES) == 0) {
+ pd->edit_mesh.do_faces = false;
+ pd->edit_mesh.do_zbufclip = false;
+ }
+ if ((flag & V3D_OVERLAY_EDIT_EDGES) == 0) {
+ if ((tsettings->selectmode & SCE_SELECT_EDGE) == 0) {
+ if ((v3d->shading.type < OB_SOLID) || (v3d->shading.flag & V3D_SHADING_XRAY)) {
+ /* Special case, when drawing wire, draw edges, see: T67637. */
+ }
+ else {
+ pd->edit_mesh.do_edges = false;
+ }
+ }
+ }
+
+ float backwire_opacity = (pd->edit_mesh.do_zbufclip) ? v3d->overlay.backwire_opacity : 1.0f;
+ float face_alpha = (do_occlude_wire || !pd->edit_mesh.do_faces) ? 0.0f : 1.0f;
+ GPUTexture **depth_tex = (pd->edit_mesh.do_zbufclip) ? &dtxl->depth : &txl->dummy_depth_tx;
+
+ if (select_face && !pd->edit_mesh.do_faces && pd->edit_mesh.do_edges) {
+ /* Force display of face centers in this case because that's
+ * the only way to see if a face is selected. */
+ show_face_dots = true;
+ }
+
+ {
+ /* TODO(fclem) Shouldn't this be going into the paint overlay? */
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->edit_mesh_weight_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_paint_weight();
+ pd->edit_mesh_weight_grp = grp = DRW_shgroup_create(sh, psl->edit_mesh_weight_ps);
+ DRW_shgroup_uniform_float_copy(grp, "opacity", 1.0);
+ DRW_shgroup_uniform_bool_copy(grp, "drawContours", false);
+ DRW_shgroup_uniform_texture(grp, "colorramp", G_draw.weight_ramp);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ }
+ /* Run Twice for in-front passes. */
+ for (int i = 0; i < 2; i++) {
+ /* Complementary Depth Pass */
+ state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
+ DRW_PASS_CREATE(psl->edit_mesh_depth_ps[i], state | pd->clipping_state);
+
+ sh = OVERLAY_shader_depth_only();
+ pd->edit_mesh_depth_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_depth_ps[i]);
+ }
+ {
+ /* Normals */
+ state = DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
+ (pd->edit_mesh.do_zbufclip ? DRW_STATE_BLEND_ALPHA : 0);
+ DRW_PASS_CREATE(psl->edit_mesh_normals_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_edit_mesh_normal();
+ pd->edit_mesh_normals_grp = grp = DRW_shgroup_create(sh, psl->edit_mesh_normals_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "normalSize", v3d->overlay.normals_length);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", backwire_opacity);
+ DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
+ }
+ {
+ /* Mesh Analysis Pass */
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->edit_mesh_analysis_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_edit_mesh_analysis();
+ pd->edit_mesh_analysis_grp = grp = DRW_shgroup_create(sh, psl->edit_mesh_analysis_ps);
+ DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
+ }
+ /* Run Twice for in-front passes. */
+ for (int i = 0; i < 2; i++) {
+ GPUShader *edge_sh = OVERLAY_shader_edit_mesh_edge(!select_vert);
+ GPUShader *face_sh = OVERLAY_shader_edit_mesh_face();
+ const bool do_zbufclip = (i == 0 && pd->edit_mesh.do_zbufclip);
+ DRWState state_common = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_BLEND_ALPHA;
+ /* Faces */
+ /* Cage geom needs to be offsetted to avoid Z-fighting. */
+ for (int j = 0; j < 2; j++) {
+ DRWPass **edit_face_ps = (j == 0) ? &psl->edit_mesh_faces_ps[i] :
+ &psl->edit_mesh_faces_cage_ps[i];
+ DRWShadingGroup **shgrp = (j == 0) ? &pd->edit_mesh_faces_grp[i] :
+ &pd->edit_mesh_faces_cage_grp[i];
+ state = state_common;
+ DRW_PASS_CREATE(*edit_face_ps, state | pd->clipping_state);
+
+ grp = *shgrp = DRW_shgroup_create(face_sh, *edit_face_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_ivec4(grp, "dataMask", mask, 1);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", face_alpha);
+ DRW_shgroup_uniform_bool_copy(grp, "selectFaces", select_face);
+ }
+
+ if (do_zbufclip) {
+ state_common |= DRW_STATE_WRITE_DEPTH;
+ // state_common &= ~DRW_STATE_BLEND_ALPHA;
+ }
+
+ /* Edges */
+ /* Change first vertex convention to match blender loop structure. */
+ state = state_common | DRW_STATE_FIRST_VERTEX_CONVENTION;
+ DRW_PASS_CREATE(psl->edit_mesh_edges_ps[i], state | pd->clipping_state);
+
+ grp = pd->edit_mesh_edges_grp[i] = DRW_shgroup_create(edge_sh, psl->edit_mesh_edges_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_ivec4(grp, "dataMask", mask, 1);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", backwire_opacity);
+ DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
+ DRW_shgroup_uniform_bool_copy(grp, "selectEdges", pd->edit_mesh.do_edges || select_edge);
+
+ /* Verts */
+ DRW_PASS_CREATE(psl->edit_mesh_verts_ps[i], state | pd->clipping_state);
+
+ if (select_vert) {
+ sh = OVERLAY_shader_edit_mesh_vert();
+ grp = pd->edit_mesh_verts_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_verts_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", backwire_opacity);
+ DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
+
+ sh = OVERLAY_shader_edit_mesh_skin_root();
+ grp = pd->edit_mesh_skin_roots_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_verts_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ }
+ /* Facedots */
+ if (select_face && show_face_dots) {
+ sh = OVERLAY_shader_edit_mesh_facedot();
+ grp = pd->edit_mesh_facedots_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_verts_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", backwire_opacity);
+ DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
+ DRW_shgroup_state_enable(grp, DRW_STATE_WRITE_DEPTH);
+ }
+ else {
+ pd->edit_mesh_facedots_grp[i] = NULL;
+ }
+ }
+}
+
+static void overlay_edit_mesh_add_ob_to_pass(OVERLAY_PrivateData *pd, Object *ob, bool in_front)
+{
+ struct GPUBatch *geom_tris, *geom_verts, *geom_edges, *geom_fcenter, *skin_roots, *circle;
+ DRWShadingGroup *vert_shgrp, *edge_shgrp, *fdot_shgrp, *face_shgrp, *skin_roots_shgrp;
+
+ bool has_edit_mesh_cage = false;
+ bool has_skin_roots = false;
+ /* TODO: Should be its own function. */
+ Mesh *me = (Mesh *)ob->data;
+ BMEditMesh *embm = me->edit_mesh;
+ if (embm) {
+ has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final);
+ has_skin_roots = CustomData_get_offset(&embm->bm->vdata, CD_MVERT_SKIN) != -1;
+ }
+
+ vert_shgrp = pd->edit_mesh_verts_grp[in_front];
+ edge_shgrp = pd->edit_mesh_edges_grp[in_front];
+ fdot_shgrp = pd->edit_mesh_facedots_grp[in_front];
+ face_shgrp = (has_edit_mesh_cage) ? pd->edit_mesh_faces_cage_grp[in_front] :
+ pd->edit_mesh_faces_grp[in_front];
+ skin_roots_shgrp = pd->edit_mesh_skin_roots_grp[in_front];
+
+ geom_edges = DRW_mesh_batch_cache_get_edit_edges(ob->data);
+ geom_tris = DRW_mesh_batch_cache_get_edit_triangles(ob->data);
+ DRW_shgroup_call_no_cull(edge_shgrp, geom_edges, ob);
+ DRW_shgroup_call_no_cull(face_shgrp, geom_tris, ob);
+
+ if (pd->edit_mesh.select_vert) {
+ geom_verts = DRW_mesh_batch_cache_get_edit_vertices(ob->data);
+ DRW_shgroup_call_no_cull(vert_shgrp, geom_verts, ob);
+
+ if (has_skin_roots) {
+ circle = DRW_cache_circle_get();
+ skin_roots = DRW_mesh_batch_cache_get_edit_skin_roots(ob->data);
+ DRW_shgroup_call_instances_with_attribs(skin_roots_shgrp, ob, circle, skin_roots);
+ }
+ }
+
+ if (fdot_shgrp) {
+ geom_fcenter = DRW_mesh_batch_cache_get_edit_facedots(ob->data);
+ DRW_shgroup_call_no_cull(fdot_shgrp, geom_fcenter, ob);
+ }
+}
+
+void OVERLAY_edit_mesh_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUBatch *geom = NULL;
+
+ bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+ bool do_occlude_wire = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 0;
+ bool do_show_weight = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_WEIGHT) != 0;
+ bool do_show_mesh_analysis = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_STATVIS) != 0;
+ bool fnormals_do = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_FACE_NORMALS) != 0;
+ bool vnormals_do = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_VERT_NORMALS) != 0;
+ bool lnormals_do = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_LOOP_NORMALS) != 0;
+
+ if (do_show_weight) {
+ geom = DRW_cache_mesh_surface_weights_get(ob);
+ DRW_shgroup_call_no_cull(pd->edit_mesh_weight_grp, geom, ob);
+ }
+ else if (do_show_mesh_analysis && !pd->xray_enabled) {
+ geom = DRW_cache_mesh_surface_mesh_analysis_get(ob);
+ if (geom) {
+ DRW_shgroup_call_no_cull(pd->edit_mesh_analysis_grp, geom, ob);
+ }
+ }
+
+ if (do_occlude_wire || do_in_front) {
+ geom = DRW_cache_mesh_surface_get(ob);
+ DRW_shgroup_call_no_cull(pd->edit_mesh_depth_grp[do_in_front], geom, ob);
+ }
+
+ if (vnormals_do || lnormals_do || fnormals_do) {
+ struct GPUBatch *normal_geom = DRW_cache_normal_arrow_get();
+ if (vnormals_do) {
+ geom = DRW_mesh_batch_cache_get_edit_vnors(ob->data);
+ DRW_shgroup_call_instances_with_attribs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
+ }
+ if (lnormals_do) {
+ geom = DRW_mesh_batch_cache_get_edit_lnors(ob->data);
+ DRW_shgroup_call_instances_with_attribs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
+ }
+ if (fnormals_do) {
+ geom = DRW_mesh_batch_cache_get_edit_facedots(ob->data);
+ DRW_shgroup_call_instances_with_attribs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
+ }
+ }
+
+ if (pd->edit_mesh.do_zbufclip) {
+ overlay_edit_mesh_add_ob_to_pass(pd, ob, false);
+ }
+ else {
+ overlay_edit_mesh_add_ob_to_pass(pd, ob, do_in_front);
+ }
+
+ pd->edit_mesh.ghost_ob += (ob->dtx & OB_DRAWXRAY) ? 1 : 0;
+ pd->edit_mesh.edit_ob += 1;
+
+ if (DRW_state_show_text() && (pd->edit_mesh.flag & OVERLAY_EDIT_TEXT)) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ DRW_text_edit_mesh_measure_stats(draw_ctx->ar, draw_ctx->v3d, ob, &draw_ctx->scene->unit);
+ }
+}
+
+static void overlay_edit_mesh_draw_components(OVERLAY_PassList *psl,
+ OVERLAY_PrivateData *pd,
+ bool in_front)
+{
+ DRW_view_set_active(pd->view_edit_faces);
+ DRW_draw_pass(psl->edit_mesh_faces_ps[in_front]);
+
+ DRW_view_set_active(pd->view_edit_faces_cage);
+ DRW_draw_pass(psl->edit_mesh_faces_cage_ps[in_front]);
+
+ DRW_view_set_active(pd->view_edit_edges);
+ DRW_draw_pass(psl->edit_mesh_edges_ps[in_front]);
+
+ DRW_view_set_active(pd->view_edit_verts);
+ DRW_draw_pass(psl->edit_mesh_verts_ps[in_front]);
+
+ DRW_view_set_active(pd->view_default);
+}
+
+void OVERLAY_edit_mesh_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+
+ DRW_draw_pass(psl->edit_mesh_weight_ps);
+ DRW_draw_pass(psl->edit_mesh_analysis_ps);
+
+ DRW_draw_pass(psl->edit_mesh_depth_ps[NOT_IN_FRONT]);
+
+ if (pd->edit_mesh.do_zbufclip) {
+ DRW_draw_pass(psl->edit_mesh_depth_ps[IN_FRONT]);
+
+ /* render facefill */
+ DRW_view_set_active(pd->view_edit_faces);
+ DRW_draw_pass(psl->edit_mesh_faces_ps[NOT_IN_FRONT]);
+
+ DRW_view_set_active(pd->view_edit_faces_cage);
+ DRW_draw_pass(psl->edit_mesh_faces_cage_ps[NOT_IN_FRONT]);
+
+ DRW_view_set_active(pd->view_default);
+
+ GPU_framebuffer_bind(fbl->overlay_in_front_fb);
+ GPU_framebuffer_clear_depth(fbl->overlay_in_front_fb, 1.0f);
+ DRW_draw_pass(psl->edit_mesh_normals_ps);
+
+ DRW_view_set_active(pd->view_edit_edges);
+ DRW_draw_pass(psl->edit_mesh_edges_ps[NOT_IN_FRONT]);
+
+ DRW_view_set_active(pd->view_edit_verts);
+ DRW_draw_pass(psl->edit_mesh_verts_ps[NOT_IN_FRONT]);
+
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+ else {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+
+ DRW_draw_pass(psl->edit_mesh_normals_ps);
+ overlay_edit_mesh_draw_components(psl, pd, false);
+
+ if (v3d->shading.type == OB_SOLID && pd->edit_mesh.ghost_ob == 1 &&
+ pd->edit_mesh.edit_ob == 1) {
+ /* In the case of single ghost object edit (common case for retopology):
+ * we clear the depth buffer so that only the depth of the retopo mesh
+ * is occluding the edit cage. */
+ GPU_framebuffer_clear_depth(fbl->overlay_default_fb, 1.0f);
+ }
+
+ DRW_draw_pass(psl->edit_mesh_depth_ps[IN_FRONT]);
+ overlay_edit_mesh_draw_components(psl, pd, true);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_edit_text.c b/source/blender/draw/engines/overlay/overlay_edit_text.c
new file mode 100644
index 00000000000..d8edf34168e
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_edit_text.c
@@ -0,0 +1,201 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_font.h"
+
+#include "DNA_curve_types.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_edit_text_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ DRWShadingGroup *grp;
+ GPUShader *sh;
+ DRWState state;
+
+ pd->edit_curve.show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
+ pd->shdata.edit_curve_normal_length = v3d->overlay.normals_length;
+
+ /* Run Twice for in-front passes. */
+ for (int i = 0; i < 2; i++) {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH;
+ state |= ((i == 0) ? DRW_STATE_DEPTH_LESS_EQUAL : DRW_STATE_DEPTH_ALWAYS);
+ DRW_PASS_CREATE(psl->edit_text_wire_ps[i], state | pd->clipping_state);
+
+ sh = OVERLAY_shader_uniform_color();
+ pd->edit_text_wire_grp[i] = grp = DRW_shgroup_create(sh, psl->edit_text_wire_ps[i]);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", G_draw.block.colorWire);
+ }
+ {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_LOGIC_INVERT;
+ DRW_PASS_CREATE(psl->edit_text_overlay_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_uniform_color();
+ pd->edit_text_overlay_grp = DRW_shgroup_create(sh, psl->edit_text_overlay_ps);
+ }
+}
+
+/* Use 2D quad corners to create a matrix that set
+ * a [-1..1] quad at the right position. */
+static void v2_quad_corners_to_mat4(float corners[4][2], float r_mat[4][4])
+{
+ unit_m4(r_mat);
+ sub_v2_v2v2(r_mat[0], corners[1], corners[0]);
+ sub_v2_v2v2(r_mat[1], corners[3], corners[0]);
+ mul_v2_fl(r_mat[0], 0.5f);
+ mul_v2_fl(r_mat[1], 0.5f);
+ copy_v2_v2(r_mat[3], corners[0]);
+ add_v2_v2(r_mat[3], r_mat[0]);
+ add_v2_v2(r_mat[3], r_mat[1]);
+}
+
+static void edit_text_cache_populate_select(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const Curve *cu = ob->data;
+ EditFont *ef = cu->editfont;
+ float final_mat[4][4], box[4][2];
+ struct GPUBatch *geom = DRW_cache_quad_get();
+
+ for (int i = 0; i < ef->selboxes_len; i++) {
+ EditFontSelBox *sb = &ef->selboxes[i];
+
+ float selboxw;
+ if (i + 1 != ef->selboxes_len) {
+ if (ef->selboxes[i + 1].y == sb->y) {
+ selboxw = ef->selboxes[i + 1].x - sb->x;
+ }
+ else {
+ selboxw = sb->w;
+ }
+ }
+ else {
+ selboxw = sb->w;
+ }
+ /* NOTE: v2_quad_corners_to_mat4 don't need the 3rd corner. */
+ if (sb->rot == 0.0f) {
+ copy_v2_fl2(box[0], sb->x, sb->y);
+ copy_v2_fl2(box[1], sb->x + selboxw, sb->y);
+ copy_v2_fl2(box[3], sb->x, sb->y + sb->h);
+ }
+ else {
+ float mat[2][2];
+ angle_to_mat2(mat, sb->rot);
+ copy_v2_fl2(box[0], sb->x, sb->y);
+ mul_v2_v2fl(box[1], mat[0], selboxw);
+ add_v2_v2(box[1], &sb->x);
+ mul_v2_v2fl(box[3], mat[1], sb->h);
+ add_v2_v2(box[3], &sb->x);
+ }
+ v2_quad_corners_to_mat4(box, final_mat);
+ mul_m4_m4m4(final_mat, ob->obmat, final_mat);
+
+ DRW_shgroup_call_obmat(pd->edit_text_overlay_grp, geom, final_mat);
+ }
+}
+
+static void edit_text_cache_populate_cursor(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const Curve *cu = ob->data;
+ EditFont *edit_font = cu->editfont;
+ float(*cursor)[2] = edit_font->textcurs;
+ float mat[4][4];
+
+ v2_quad_corners_to_mat4(cursor, mat);
+ mul_m4_m4m4(mat, ob->obmat, mat);
+
+ struct GPUBatch *geom = DRW_cache_quad_get();
+ DRW_shgroup_call_obmat(pd->edit_text_overlay_grp, geom, mat);
+}
+
+static void edit_text_cache_populate_boxes(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ const Curve *cu = ob->data;
+
+ for (int i = 0; i < cu->totbox; i++) {
+ TextBox *tb = &cu->tb[i];
+ const bool is_active = (i == (cu->actbox - 1));
+ float *color = is_active ? G_draw.block.colorActive : G_draw.block.colorWire;
+
+ if ((tb->w != 0.0f) || (tb->h != 0.0f)) {
+ float vecs[4][3];
+ vecs[0][0] = vecs[1][0] = vecs[2][0] = vecs[3][0] = cu->xof + tb->x;
+ vecs[0][1] = vecs[1][1] = vecs[2][1] = vecs[3][1] = cu->yof + tb->y + cu->fsize_realtime;
+ vecs[0][2] = vecs[1][2] = vecs[2][2] = vecs[3][2] = 0.001;
+
+ vecs[1][0] += tb->w;
+ vecs[2][0] += tb->w;
+ vecs[2][1] -= tb->h;
+ vecs[3][1] -= tb->h;
+
+ for (int j = 0; j < 4; j++) {
+ mul_v3_m4v3(vecs[j], ob->obmat, vecs[j]);
+ }
+ for (int j = 0; j < 4; j++) {
+ OVERLAY_extra_line_dashed(cb, vecs[j], vecs[(j + 1) % 4], color);
+ }
+ }
+ }
+}
+
+void OVERLAY_edit_text_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ Curve *cu = ob->data;
+ struct GPUBatch *geom;
+ bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+
+ bool has_surface = (cu->flag & (CU_FRONT | CU_BACK)) || cu->ext1 != 0.0f || cu->ext2 != 0.0f;
+ if ((cu->flag & CU_FAST) || !has_surface) {
+ geom = DRW_cache_text_edge_wire_get(ob);
+ if (geom) {
+ DRW_shgroup_call(pd->edit_text_wire_grp[do_in_front], geom, ob);
+ }
+ }
+ else {
+ /* object mode draws */
+ }
+
+ edit_text_cache_populate_select(vedata, ob);
+ edit_text_cache_populate_cursor(vedata, ob);
+ edit_text_cache_populate_boxes(vedata, ob);
+}
+
+void OVERLAY_edit_text_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_view_set_active(NULL);
+
+ DRW_draw_pass(psl->edit_text_wire_ps[0]);
+ DRW_draw_pass(psl->edit_text_wire_ps[1]);
+
+ DRW_draw_pass(psl->edit_text_overlay_ps);
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
new file mode 100644
index 00000000000..667172e5bb5
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -0,0 +1,491 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Engine for drawing a selection map where the pixels indicate the selection indices.
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "ED_view3d.h"
+
+#include "BKE_object.h"
+
+#include "overlay_engine.h"
+#include "overlay_private.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Engine Callbacks
+ * \{ */
+
+static void OVERLAY_engine_init(void *vedata)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_StorageList *stl = data->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const RegionView3D *rv3d = draw_ctx->rv3d;
+ const View3D *v3d = draw_ctx->v3d;
+
+ if (!stl->pd) {
+ /* Alloc transient pointers */
+ stl->pd = MEM_callocN(sizeof(*stl->pd), __func__);
+ }
+
+ OVERLAY_PrivateData *pd = stl->pd;
+ View3DOverlay overlay;
+ short v3d_flag, v3d_gridflag;
+
+ pd->hide_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) != 0;
+ pd->ctx_mode = CTX_data_mode_enum_ex(
+ draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
+
+ if (!pd->hide_overlays) {
+ overlay = v3d->overlay;
+ v3d_flag = v3d->flag;
+ v3d_gridflag = v3d->gridflag;
+ }
+ else {
+ memset(&overlay, 0, sizeof(overlay));
+ v3d_flag = 0;
+ v3d_gridflag = 0;
+ overlay.flag = V3D_OVERLAY_HIDE_TEXT | V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_BONES |
+ V3D_OVERLAY_HIDE_OBJECT_XTRAS | V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
+ }
+
+ if (v3d->shading.type == OB_WIRE) {
+ overlay.flag |= V3D_OVERLAY_WIREFRAMES;
+ }
+
+ /* Check if anything changed, and if so, reset AA. */
+ if (v3d_flag != pd->v3d_flag || pd->v3d_gridflag != v3d_gridflag ||
+ memcmp(&pd->overlay, &overlay, sizeof(overlay))) {
+ pd->overlay = overlay;
+ pd->v3d_flag = v3d_flag;
+ pd->v3d_gridflag = v3d_gridflag;
+ OVERLAY_antialiasing_reset(vedata);
+ }
+
+ pd->wireframe_mode = (v3d->shading.type == OB_WIRE);
+ pd->clipping_state = (rv3d->rflag & RV3D_CLIPPING) ? DRW_STATE_CLIP_PLANES : 0;
+ pd->xray_enabled = XRAY_ACTIVE(v3d);
+ pd->xray_enabled_and_not_wire = pd->xray_enabled && v3d->shading.type > OB_WIRE;
+ pd->clear_in_front = (v3d->shading.type != OB_SOLID);
+
+ OVERLAY_antialiasing_init(vedata);
+
+ switch (stl->pd->ctx_mode) {
+ case CTX_MODE_EDIT_MESH:
+ OVERLAY_edit_mesh_init(vedata);
+ break;
+ default:
+ /* Nothing to do. */
+ break;
+ }
+ OVERLAY_facing_init(vedata);
+ OVERLAY_grid_init(vedata);
+ OVERLAY_image_init(vedata);
+ OVERLAY_outline_init(vedata);
+ OVERLAY_wireframe_init(vedata);
+}
+
+static void OVERLAY_cache_init(void *vedata)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_StorageList *stl = data->stl;
+ OVERLAY_PrivateData *pd = stl->pd;
+
+ switch (pd->ctx_mode) {
+ case CTX_MODE_EDIT_MESH:
+ OVERLAY_edit_mesh_cache_init(vedata);
+ break;
+ case CTX_MODE_EDIT_SURFACE:
+ case CTX_MODE_EDIT_CURVE:
+ OVERLAY_edit_curve_cache_init(vedata);
+ break;
+ case CTX_MODE_EDIT_TEXT:
+ OVERLAY_edit_text_cache_init(vedata);
+ break;
+ case CTX_MODE_EDIT_ARMATURE:
+ break;
+ case CTX_MODE_EDIT_METABALL:
+ break;
+ case CTX_MODE_EDIT_LATTICE:
+ OVERLAY_edit_lattice_cache_init(vedata);
+ break;
+ case CTX_MODE_PARTICLE:
+ OVERLAY_edit_particle_cache_init(vedata);
+ break;
+ case CTX_MODE_POSE:
+ case CTX_MODE_PAINT_WEIGHT:
+ case CTX_MODE_PAINT_VERTEX:
+ case CTX_MODE_PAINT_TEXTURE:
+ OVERLAY_paint_cache_init(vedata);
+ break;
+ case CTX_MODE_SCULPT:
+ OVERLAY_sculpt_cache_init(vedata);
+ break;
+ case CTX_MODE_OBJECT:
+ case CTX_MODE_PAINT_GPENCIL:
+ case CTX_MODE_EDIT_GPENCIL:
+ case CTX_MODE_SCULPT_GPENCIL:
+ case CTX_MODE_WEIGHT_GPENCIL:
+ break;
+ default:
+ BLI_assert(!"Draw mode invalid");
+ break;
+ }
+ OVERLAY_antialiasing_cache_init(vedata);
+ OVERLAY_armature_cache_init(vedata);
+ OVERLAY_extra_cache_init(vedata);
+ OVERLAY_facing_cache_init(vedata);
+ OVERLAY_grid_cache_init(vedata);
+ OVERLAY_image_cache_init(vedata);
+ OVERLAY_metaball_cache_init(vedata);
+ OVERLAY_motion_path_cache_init(vedata);
+ OVERLAY_outline_cache_init(vedata);
+ OVERLAY_particle_cache_init(vedata);
+ OVERLAY_wireframe_cache_init(vedata);
+}
+
+BLI_INLINE OVERLAY_DupliData *OVERLAY_duplidata_get(Object *ob, void *vedata, bool *do_init)
+{
+ OVERLAY_DupliData **dupli_data = (OVERLAY_DupliData **)DRW_duplidata_get(vedata);
+ *do_init = false;
+ if (!ELEM(ob->type, OB_MESH, OB_SURF, OB_LATTICE, OB_CURVE, OB_FONT)) {
+ return NULL;
+ }
+
+ if (dupli_data) {
+ if (*dupli_data == NULL) {
+ *dupli_data = MEM_callocN(sizeof(OVERLAY_DupliData), __func__);
+ *do_init = true;
+ }
+ else if ((*dupli_data)->base_flag != ob->base_flag) {
+ /* Select state might have change, reinit. */
+ *do_init = true;
+ }
+ return *dupli_data;
+ }
+ return NULL;
+}
+
+static void OVERLAY_cache_populate(void *vedata, Object *ob)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_PrivateData *pd = data->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool is_select = DRW_state_is_select();
+ const bool renderable = DRW_object_is_renderable(ob);
+ const bool in_pose_mode = ob->type == OB_ARMATURE && OVERLAY_armature_is_pose_mode(ob, draw_ctx);
+ const bool in_edit_mode = BKE_object_is_in_editmode(ob);
+ const bool in_particle_edit_mode = ob->mode == OB_MODE_PARTICLE_EDIT;
+ const bool in_paint_mode = (ob == draw_ctx->obact) &&
+ (draw_ctx->object_mode & OB_MODE_ALL_PAINT);
+ const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != NULL);
+ const bool has_surface = ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_MBALL, OB_FONT);
+ const bool draw_surface = !((ob->dt < OB_WIRE) || (!renderable && (ob->dt != OB_WIRE)));
+ const bool draw_facing = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION);
+ const bool draw_bones = (pd->overlay.flag & V3D_OVERLAY_HIDE_BONES) == 0;
+ const bool draw_wires = draw_surface && has_surface &&
+ (pd->wireframe_mode || !pd->hide_overlays);
+ const bool draw_outlines = !in_edit_mode && !in_paint_mode && renderable &&
+ (pd->v3d_flag & V3D_SELECT_OUTLINE) &&
+ ((ob->base_flag & BASE_SELECTED) ||
+ (is_select && ob->type == OB_LIGHTPROBE));
+ const bool draw_bone_selection = (ob->type == OB_MESH) && pd->armature.do_pose_fade_geom &&
+ !is_select;
+ const bool draw_extras =
+ ((pd->overlay.flag & V3D_OVERLAY_HIDE_OBJECT_XTRAS) == 0) ||
+ /* Show if this is the camera we're looking through since it's useful for selecting. */
+ ((draw_ctx->rv3d->persp == RV3D_CAMOB) && ((ID *)draw_ctx->v3d->camera == ob->id.orig_id));
+
+ const bool draw_motion_paths = (pd->overlay.flag & V3D_OVERLAY_HIDE_MOTION_PATHS) == 0;
+
+ bool do_init;
+ OVERLAY_DupliData *dupli = OVERLAY_duplidata_get(ob, vedata, &do_init);
+
+ if (draw_facing) {
+ OVERLAY_facing_cache_populate(vedata, ob);
+ }
+ if (draw_wires) {
+ OVERLAY_wireframe_cache_populate(vedata, ob, dupli, do_init);
+ }
+ if (draw_outlines) {
+ OVERLAY_outline_cache_populate(vedata, ob, dupli, do_init);
+ }
+ if (draw_bone_selection) {
+ OVERLAY_pose_cache_populate(vedata, ob);
+ }
+
+ if (in_edit_mode) {
+ switch (ob->type) {
+ case OB_MESH:
+ OVERLAY_edit_mesh_cache_populate(vedata, ob);
+ break;
+ case OB_ARMATURE:
+ if (draw_bones) {
+ OVERLAY_edit_armature_cache_populate(vedata, ob);
+ }
+ break;
+ case OB_CURVE:
+ OVERLAY_edit_curve_cache_populate(vedata, ob);
+ break;
+ case OB_SURF:
+ OVERLAY_edit_surf_cache_populate(vedata, ob);
+ break;
+ case OB_LATTICE:
+ OVERLAY_edit_lattice_cache_populate(vedata, ob);
+ break;
+ case OB_MBALL:
+ OVERLAY_edit_metaball_cache_populate(vedata, ob);
+ break;
+ case OB_FONT:
+ OVERLAY_edit_text_cache_populate(vedata, ob);
+ break;
+ }
+ }
+ else if (in_pose_mode && draw_bones) {
+ OVERLAY_pose_armature_cache_populate(vedata, ob);
+ }
+ else if (in_paint_mode) {
+ switch (draw_ctx->object_mode) {
+ case OB_MODE_VERTEX_PAINT:
+ OVERLAY_paint_vertex_cache_populate(vedata, ob);
+ break;
+ case OB_MODE_WEIGHT_PAINT:
+ OVERLAY_paint_weight_cache_populate(vedata, ob);
+ break;
+ case OB_MODE_TEXTURE_PAINT:
+ OVERLAY_paint_texture_cache_populate(vedata, ob);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (in_particle_edit_mode) {
+ OVERLAY_edit_particle_cache_populate(vedata, ob);
+ }
+
+ if (in_sculpt_mode) {
+ OVERLAY_sculpt_cache_populate(vedata, ob);
+ }
+
+ if (draw_motion_paths) {
+ OVERLAY_motion_path_cache_populate(vedata, ob);
+ }
+
+ switch (ob->type) {
+ case OB_ARMATURE:
+ if (draw_bones && (is_select || (!in_edit_mode && !in_pose_mode))) {
+ OVERLAY_armature_cache_populate(vedata, ob);
+ }
+ break;
+ case OB_MBALL:
+ if (!in_edit_mode) {
+ OVERLAY_metaball_cache_populate(vedata, ob);
+ }
+ break;
+ case OB_GPENCIL:
+ OVERLAY_gpencil_cache_populate(vedata, ob);
+ break;
+ }
+ /* Non-Meshes */
+ if (draw_extras) {
+ switch (ob->type) {
+ case OB_EMPTY:
+ OVERLAY_empty_cache_populate(vedata, ob);
+ break;
+ case OB_LAMP:
+ OVERLAY_light_cache_populate(vedata, ob);
+ break;
+ case OB_CAMERA:
+ OVERLAY_camera_cache_populate(vedata, ob);
+ break;
+ case OB_SPEAKER:
+ OVERLAY_speaker_cache_populate(vedata, ob);
+ break;
+ case OB_LIGHTPROBE:
+ OVERLAY_lightprobe_cache_populate(vedata, ob);
+ break;
+ case OB_LATTICE:
+ OVERLAY_lattice_cache_populate(vedata, ob);
+ break;
+ }
+ }
+
+ if (!BLI_listbase_is_empty(&ob->particlesystem)) {
+ OVERLAY_particle_cache_populate(vedata, ob);
+ }
+
+ /* Relationship, object center, bounbox ... */
+ OVERLAY_extra_cache_populate(vedata, ob);
+
+ if (dupli) {
+ dupli->base_flag = ob->base_flag;
+ }
+}
+
+static void OVERLAY_cache_finish(void *vedata)
+{
+ /* TODO(fclem) Only do this when really needed. */
+ {
+ /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0);
+
+ GPU_framebuffer_ensure_config(
+ &dfbl->default_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+ GPU_framebuffer_ensure_config(
+ &dfbl->in_front_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+ }
+
+ OVERLAY_antialiasing_cache_finish(vedata);
+ OVERLAY_armature_cache_finish(vedata);
+ OVERLAY_image_cache_finish(vedata);
+}
+
+static void OVERLAY_draw_scene(void *vedata)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_PrivateData *pd = data->stl->pd;
+ OVERLAY_FramebufferList *fbl = data->fbl;
+
+ OVERLAY_antialiasing_start(vedata);
+
+ DRW_view_set_active(pd->view_default);
+
+ OVERLAY_image_draw(vedata);
+ OVERLAY_facing_draw(vedata);
+ OVERLAY_wireframe_draw(vedata);
+ OVERLAY_armature_draw(vedata);
+ OVERLAY_particle_draw(vedata);
+ OVERLAY_metaball_draw(vedata);
+ OVERLAY_extra_draw(vedata);
+
+ DRW_view_set_active(NULL);
+
+ OVERLAY_grid_draw(vedata);
+ OVERLAY_outline_draw(vedata);
+
+ DRW_view_set_active(pd->view_default);
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_in_front_fb);
+
+ /* If we are not in solid shading mode, we clear the depth. */
+ if (pd->clear_in_front) {
+ /* TODO(fclem) This clear should be done in a global place. */
+ GPU_framebuffer_clear_depth(fbl->overlay_in_front_fb, 1.0f);
+ }
+ }
+
+ OVERLAY_wireframe_in_front_draw(vedata);
+ OVERLAY_armature_in_front_draw(vedata);
+ OVERLAY_extra_in_front_draw(vedata);
+ OVERLAY_metaball_in_front_draw(vedata);
+ OVERLAY_image_in_front_draw(vedata);
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+
+ OVERLAY_motion_path_draw(vedata);
+ OVERLAY_extra_centers_draw(vedata);
+
+ switch (pd->ctx_mode) {
+ case CTX_MODE_EDIT_MESH:
+ OVERLAY_edit_mesh_draw(vedata);
+ break;
+ case CTX_MODE_EDIT_SURFACE:
+ case CTX_MODE_EDIT_CURVE:
+ OVERLAY_edit_curve_draw(vedata);
+ break;
+ case CTX_MODE_EDIT_TEXT:
+ /* Text overlay need final color for color inversion. */
+ OVERLAY_antialiasing_end(vedata);
+ OVERLAY_edit_text_draw(vedata);
+ return; /* WATCH! dont do AA twice. */
+ case CTX_MODE_EDIT_LATTICE:
+ OVERLAY_edit_lattice_draw(vedata);
+ break;
+ case CTX_MODE_POSE:
+ /* Pain overlay needs final color because of multiply blend mode. */
+ OVERLAY_antialiasing_end(vedata);
+ OVERLAY_paint_draw(vedata);
+ OVERLAY_pose_draw(vedata);
+ return; /* WATCH! dont do AA twice. */
+ case CTX_MODE_PAINT_WEIGHT:
+ case CTX_MODE_PAINT_VERTEX:
+ case CTX_MODE_PAINT_TEXTURE:
+ /* Pain overlay need final color because of multiply blend mode. */
+ OVERLAY_antialiasing_end(vedata);
+ OVERLAY_paint_draw(vedata);
+ return; /* WATCH! dont do AA twice. */
+ case CTX_MODE_PARTICLE:
+ OVERLAY_edit_particle_draw(vedata);
+ break;
+ case CTX_MODE_SCULPT:
+ OVERLAY_sculpt_draw(vedata);
+ break;
+ default:
+ break;
+ }
+
+ OVERLAY_antialiasing_end(vedata);
+}
+
+static void OVERLAY_engine_free(void)
+{
+ OVERLAY_shader_free();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Engine Type
+ * \{ */
+
+static const DrawEngineDataSize overlay_data_size = DRW_VIEWPORT_DATA_SIZE(OVERLAY_Data);
+
+DrawEngineType draw_engine_overlay_type = {
+ NULL,
+ NULL,
+ N_("Overlay"),
+ &overlay_data_size,
+ &OVERLAY_engine_init,
+ &OVERLAY_engine_free,
+ &OVERLAY_cache_init,
+ &OVERLAY_cache_populate,
+ &OVERLAY_cache_finish,
+ NULL,
+ &OVERLAY_draw_scene,
+ NULL,
+ NULL,
+ NULL,
+};
+
+/** \} */
+
+#undef SELECT_ENGINE
diff --git a/source/blender/draw/engines/overlay/overlay_engine.h b/source/blender/draw/engines/overlay/overlay_engine.h
new file mode 100644
index 00000000000..795e3805037
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_engine.h
@@ -0,0 +1,28 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#ifndef __OVERLAY_ENGINE_H__
+#define __OVERLAY_ENGINE_H__
+
+extern DrawEngineType draw_engine_overlay_type;
+
+#endif /* __OVERLAY_ENGINE_H__ */
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
new file mode 100644
index 00000000000..d088142bdef
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -0,0 +1,1586 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "UI_resources.h"
+
+#include "BKE_anim.h"
+#include "BKE_camera.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_movieclip.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_tracking.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_lightprobe_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_force_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_smoke_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_view3d.h"
+
+#include "GPU_draw.h"
+
+#include "overlay_private.h"
+
+#include "draw_common.h"
+#include "draw_manager_text.h"
+
+void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ DRW_PASS_CREATE(psl->extra_blend_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
+ DRW_PASS_CREATE(psl->extra_centers_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
+
+ for (int i = 0; i < 2; i++) {
+ /* Non Meshes Pass (Camera, empties, lights ...) */
+ struct GPUShader *sh;
+ struct GPUVertFormat *format;
+ DRWShadingGroup *grp, *grp_sub;
+
+ OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
+ OVERLAY_ExtraCallBuffers *cb = &pd->extra_call_buffers[i];
+ DRWPass **p_extra_ps = &psl->extra_ps[i];
+
+ DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(*p_extra_ps, state | pd->clipping_state | infront_state);
+
+ DRWPass *extra_ps = *p_extra_ps;
+
+#define BUF_INSTANCE DRW_shgroup_call_buffer_instance
+#define BUF_POINT(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_POINTS)
+#define BUF_LINE(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_LINES)
+
+ /* Sorted by shader to avoid state changes during render. */
+ {
+ format = formats->instance_extra;
+ sh = OVERLAY_shader_extra();
+
+ grp = DRW_shgroup_create(sh, extra_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ cb->camera_distances = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_distances_get());
+ cb->camera_frame = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_frame_get());
+ cb->camera_tria[0] = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_tria_wire_get());
+ cb->camera_tria[1] = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_tria_get());
+ cb->empty_axes = BUF_INSTANCE(grp_sub, format, DRW_cache_bone_arrows_get());
+ cb->empty_capsule_body = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_capsule_body_get());
+ cb->empty_capsule_cap = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_capsule_cap_get());
+ cb->empty_circle = BUF_INSTANCE(grp_sub, format, DRW_cache_circle_get());
+ cb->empty_cone = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_cone_get());
+ cb->empty_cube = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_cube_get());
+ cb->empty_cylinder = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_cylinder_get());
+ cb->empty_image_frame = BUF_INSTANCE(grp_sub, format, DRW_cache_quad_wires_get());
+ cb->empty_plain_axes = BUF_INSTANCE(grp_sub, format, DRW_cache_plain_axes_get());
+ cb->empty_single_arrow = BUF_INSTANCE(grp_sub, format, DRW_cache_single_arrow_get());
+ cb->empty_sphere = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_sphere_get());
+ cb->empty_sphere_solid = BUF_INSTANCE(grp_sub, format, DRW_cache_sphere_get());
+ cb->field_cone_limit = BUF_INSTANCE(grp_sub, format, DRW_cache_field_cone_limit_get());
+ cb->field_curve = BUF_INSTANCE(grp_sub, format, DRW_cache_field_curve_get());
+ cb->field_force = BUF_INSTANCE(grp_sub, format, DRW_cache_field_force_get());
+ cb->field_sphere_limit = BUF_INSTANCE(grp_sub, format, DRW_cache_field_sphere_limit_get());
+ cb->field_tube_limit = BUF_INSTANCE(grp_sub, format, DRW_cache_field_tube_limit_get());
+ cb->field_vortex = BUF_INSTANCE(grp_sub, format, DRW_cache_field_vortex_get());
+ cb->field_wind = BUF_INSTANCE(grp_sub, format, DRW_cache_field_wind_get());
+ cb->light_area[0] = BUF_INSTANCE(grp_sub, format, DRW_cache_light_area_disk_lines_get());
+ cb->light_area[1] = BUF_INSTANCE(grp_sub, format, DRW_cache_light_area_square_lines_get());
+ cb->light_point = BUF_INSTANCE(grp_sub, format, DRW_cache_light_point_lines_get());
+ cb->light_spot = BUF_INSTANCE(grp_sub, format, DRW_cache_light_spot_lines_get());
+ cb->light_sun = BUF_INSTANCE(grp_sub, format, DRW_cache_light_sun_lines_get());
+ cb->probe_cube = BUF_INSTANCE(grp_sub, format, DRW_cache_lightprobe_planar_get());
+ cb->probe_grid = BUF_INSTANCE(grp_sub, format, DRW_cache_lightprobe_grid_get());
+ cb->probe_planar = BUF_INSTANCE(grp_sub, format, DRW_cache_lightprobe_planar_get());
+ cb->speaker = BUF_INSTANCE(grp_sub, format, DRW_cache_speaker_get());
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_state_enable(grp_sub, DRW_STATE_DEPTH_ALWAYS);
+ DRW_shgroup_state_disable(grp_sub, DRW_STATE_DEPTH_LESS_EQUAL);
+ cb->origin_xform = BUF_INSTANCE(grp_sub, format, DRW_cache_bone_arrows_get());
+ }
+ {
+ format = formats->instance_extra;
+ grp = DRW_shgroup_create(sh, psl->extra_blend_ps); /* NOTE: not the same pass! */
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_state_enable(grp_sub, DRW_STATE_CULL_BACK);
+ cb->camera_volume = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_volume_get());
+ cb->camera_volume_frame = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_volume_wire_get());
+ cb->light_spot_cone_back = BUF_INSTANCE(grp_sub, format, DRW_cache_light_spot_volume_get());
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_state_enable(grp_sub, DRW_STATE_CULL_FRONT);
+ cb->light_spot_cone_front = BUF_INSTANCE(grp_sub, format, DRW_cache_light_spot_volume_get());
+ }
+ {
+ format = formats->instance_pos;
+ sh = OVERLAY_shader_extra_groundline();
+
+ grp = DRW_shgroup_create(sh, extra_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+ cb->groundline = BUF_INSTANCE(grp, format, DRW_cache_groundline_get());
+ }
+ {
+ sh = OVERLAY_shader_extra_wire(false);
+
+ grp = DRW_shgroup_create(sh, extra_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+ cb->extra_dashed_lines = BUF_LINE(grp, formats->pos_color);
+ cb->extra_lines = BUF_LINE(grp, formats->wire_extra);
+ }
+ {
+ sh = OVERLAY_shader_extra_wire(true);
+
+ cb->extra_wire = grp = DRW_shgroup_create(sh, extra_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ }
+ {
+ sh = OVERLAY_shader_extra_loose_point();
+
+ cb->extra_loose_points = grp = DRW_shgroup_create(sh, extra_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ }
+ {
+ format = formats->pos;
+ sh = OVERLAY_shader_extra_point();
+
+ grp = DRW_shgroup_create(sh, psl->extra_centers_ps); /* NOTE: not the same pass! */
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorActive);
+ cb->center_active = BUF_POINT(grp_sub, format);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorSelect);
+ cb->center_selected = BUF_POINT(grp_sub, format);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorDeselect);
+ cb->center_deselected = BUF_POINT(grp_sub, format);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorLibrarySelect);
+ cb->center_selected_lib = BUF_POINT(grp_sub, format);
+
+ grp_sub = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorLibrary);
+ cb->center_deselected_lib = BUF_POINT(grp_sub, format);
+ }
+ }
+}
+
+void OVERLAY_extra_line_dashed(OVERLAY_ExtraCallBuffers *cb,
+ const float start[3],
+ const float end[3],
+ const float color[4])
+{
+ DRW_buffer_add_entry(cb->extra_dashed_lines, end, color);
+ DRW_buffer_add_entry(cb->extra_dashed_lines, start, color);
+}
+
+void OVERLAY_extra_line(OVERLAY_ExtraCallBuffers *cb,
+ const float start[3],
+ const float end[3],
+ const int color_id)
+{
+ DRW_buffer_add_entry(cb->extra_lines, start, &color_id);
+ DRW_buffer_add_entry(cb->extra_lines, end, &color_id);
+}
+
+OVERLAY_ExtraCallBuffers *OVERLAY_extra_call_buffer_get(OVERLAY_Data *vedata, Object *ob)
+{
+ bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ return &pd->extra_call_buffers[do_in_front];
+}
+
+void OVERLAY_extra_loose_points(OVERLAY_ExtraCallBuffers *cb,
+ struct GPUBatch *geom,
+ const float mat[4][4],
+ const float color[4])
+{
+ float draw_mat[4][4];
+ pack_v4_in_mat4(draw_mat, mat, color);
+ DRW_shgroup_call_obmat(cb->extra_loose_points, geom, draw_mat);
+}
+
+void OVERLAY_extra_wire(OVERLAY_ExtraCallBuffers *cb,
+ struct GPUBatch *geom,
+ const float mat[4][4],
+ const float color[4])
+{
+ float draw_mat[4][4];
+ pack_v4_in_mat4(draw_mat, mat, color);
+ DRW_shgroup_call_obmat(cb->extra_wire, geom, draw_mat);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Empties
+ * \{ */
+
+void OVERLAY_empty_shape(OVERLAY_ExtraCallBuffers *cb,
+ const float mat[4][4],
+ const float draw_size,
+ const char draw_type,
+ const float color[4])
+{
+ float instdata[4][4];
+ pack_fl_in_mat4(instdata, mat, draw_size);
+
+ switch (draw_type) {
+ case OB_PLAINAXES:
+ DRW_buffer_add_entry(cb->empty_plain_axes, color, instdata);
+ break;
+ case OB_SINGLE_ARROW:
+ DRW_buffer_add_entry(cb->empty_single_arrow, color, instdata);
+ break;
+ case OB_CUBE:
+ DRW_buffer_add_entry(cb->empty_cube, color, instdata);
+ break;
+ case OB_CIRCLE:
+ DRW_buffer_add_entry(cb->empty_circle, color, instdata);
+ break;
+ case OB_EMPTY_SPHERE:
+ DRW_buffer_add_entry(cb->empty_sphere, color, instdata);
+ break;
+ case OB_EMPTY_CONE:
+ DRW_buffer_add_entry(cb->empty_cone, color, instdata);
+ break;
+ case OB_ARROWS:
+ DRW_buffer_add_entry(cb->empty_axes, color, instdata);
+ break;
+ case OB_EMPTY_IMAGE:
+ /* This only show the frame. See OVERLAY_image_empty_cache_populate() for the image. */
+ DRW_buffer_add_entry(cb->empty_image_frame, color, instdata);
+ break;
+ }
+}
+
+void OVERLAY_empty_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ if (((ob->base_flag & BASE_FROM_DUPLI) != 0) && ((ob->transflag & OB_DUPLICOLLECTION) != 0) &&
+ ob->instance_collection) {
+ return;
+ }
+
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ float *color;
+
+ switch (ob->empty_drawtype) {
+ case OB_PLAINAXES:
+ case OB_SINGLE_ARROW:
+ case OB_CUBE:
+ case OB_CIRCLE:
+ case OB_EMPTY_SPHERE:
+ case OB_EMPTY_CONE:
+ case OB_ARROWS:
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+ OVERLAY_empty_shape(cb, ob->obmat, ob->empty_drawsize, ob->empty_drawtype, color);
+ break;
+ case OB_EMPTY_IMAGE:
+ OVERLAY_image_empty_cache_populate(vedata, ob);
+ break;
+ }
+}
+
+static void OVERLAY_bounds(
+ OVERLAY_ExtraCallBuffers *cb, Object *ob, int theme_id, char boundtype, bool around_origin)
+{
+ float color[4], center[3], size[3], tmp[4][4], final_mat[4][4];
+ BoundBox bb_local;
+
+ if (ob->type == OB_MBALL && !BKE_mball_is_basis(ob)) {
+ return;
+ }
+
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+
+ if (bb == NULL) {
+ const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
+ bb = &bb_local;
+ BKE_boundbox_init_from_minmax(bb, min, max);
+ }
+
+ UI_GetThemeColor4fv(theme_id, color);
+ BKE_boundbox_calc_size_aabb(bb, size);
+
+ if (around_origin) {
+ zero_v3(center);
+ }
+ else {
+ BKE_boundbox_calc_center_aabb(bb, center);
+ }
+
+ switch (boundtype) {
+ case OB_BOUND_BOX:
+ size_to_mat4(tmp, size);
+ copy_v3_v3(tmp[3], center);
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_cube, color, tmp);
+ break;
+ case OB_BOUND_SPHERE:
+ size[0] = max_fff(size[0], size[1], size[2]);
+ size[1] = size[2] = size[0];
+ size_to_mat4(tmp, size);
+ copy_v3_v3(tmp[3], center);
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_sphere, color, tmp);
+ break;
+ case OB_BOUND_CYLINDER:
+ size[0] = max_ff(size[0], size[1]);
+ size[1] = size[0];
+ size_to_mat4(tmp, size);
+ copy_v3_v3(tmp[3], center);
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_cylinder, color, tmp);
+ break;
+ case OB_BOUND_CONE:
+ size[0] = max_ff(size[0], size[1]);
+ size[1] = size[0];
+ size_to_mat4(tmp, size);
+ copy_v3_v3(tmp[3], center);
+ /* Cone batch has base at 0 and is pointing towards +Y. */
+ swap_v3_v3(tmp[1], tmp[2]);
+ tmp[3][2] -= size[2];
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_cone, color, tmp);
+ break;
+ case OB_BOUND_CAPSULE:
+ size[0] = max_ff(size[0], size[1]);
+ size[1] = size[0];
+ scale_m4_fl(tmp, size[0]);
+ copy_v2_v2(tmp[3], center);
+ tmp[3][2] = center[2] + max_ff(0.0f, size[2] - size[0]);
+ mul_m4_m4m4(final_mat, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_capsule_cap, color, final_mat);
+ negate_v3(tmp[2]);
+ tmp[3][2] = center[2] - max_ff(0.0f, size[2] - size[0]);
+ mul_m4_m4m4(final_mat, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_capsule_cap, color, final_mat);
+ tmp[2][2] = max_ff(0.0f, size[2] * 2.0f - size[0] * 2.0f);
+ mul_m4_m4m4(final_mat, ob->obmat, tmp);
+ DRW_buffer_add_entry(cb->empty_capsule_body, color, final_mat);
+ break;
+ }
+}
+
+static void OVERLAY_collision(OVERLAY_ExtraCallBuffers *cb, Object *ob, int theme_id)
+{
+ switch (ob->rigidbody_object->shape) {
+ case RB_SHAPE_BOX:
+ OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_BOX, true);
+ break;
+ case RB_SHAPE_SPHERE:
+ OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_SPHERE, true);
+ break;
+ case RB_SHAPE_CONE:
+ OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_CONE, true);
+ break;
+ case RB_SHAPE_CYLINDER:
+ OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_CYLINDER, true);
+ break;
+ case RB_SHAPE_CAPSULE:
+ OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_CAPSULE, true);
+ break;
+ }
+}
+
+static void OVERLAY_texture_space(OVERLAY_ExtraCallBuffers *cb, Object *ob, int theme_id)
+{
+ if (ob->data == NULL) {
+ return;
+ }
+
+ ID *ob_data = ob->data;
+ float *texcoloc = NULL;
+ float *texcosize = NULL;
+
+ switch (GS(ob_data->name)) {
+ case ID_ME:
+ BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize);
+ break;
+ case ID_CU: {
+ Curve *cu = (Curve *)ob_data;
+ BKE_curve_texspace_ensure(cu);
+ texcoloc = cu->loc;
+ texcosize = cu->size;
+ break;
+ }
+ case ID_MB: {
+ MetaBall *mb = (MetaBall *)ob_data;
+ texcoloc = mb->loc;
+ texcosize = mb->size;
+ break;
+ }
+ default:
+ BLI_assert(0);
+ }
+
+ float mat[4][4], color[4];
+ size_to_mat4(mat, texcosize);
+ copy_v3_v3(mat[3], texcoloc);
+
+ mul_m4_m4m4(mat, ob->obmat, mat);
+
+ UI_GetThemeColor4fv(theme_id, color);
+
+ DRW_buffer_add_entry(cb->empty_cube, color, mat);
+}
+
+static void OVERLAY_forcefield(OVERLAY_ExtraCallBuffers *cb, Object *ob, ViewLayer *view_layer)
+{
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ float *color = DRW_color_background_blend_get(theme_id);
+ PartDeflect *pd = ob->pd;
+ Curve *cu = (ob->type == OB_CURVE) ? ob->data : NULL;
+
+ union {
+ float mat[4][4];
+ struct {
+ float _pad00[3], size_x;
+ float _pad01[3], size_y;
+ float _pad02[3], size_z;
+ float pos[3], _pad03[1];
+ };
+ } instdata;
+
+ copy_m4_m4(instdata.mat, ob->obmat);
+ instdata.size_x = instdata.size_y = instdata.size_z = ob->empty_drawsize;
+
+ switch (pd->forcefield) {
+ case PFIELD_FORCE:
+ DRW_buffer_add_entry(cb->field_force, color, &instdata);
+ break;
+ case PFIELD_WIND:
+ instdata.size_z = pd->f_strength;
+ DRW_buffer_add_entry(cb->field_wind, color, &instdata);
+ break;
+ case PFIELD_VORTEX:
+ instdata.size_y = (pd->f_strength < 0.0f) ? -instdata.size_y : instdata.size_y;
+ DRW_buffer_add_entry(cb->field_vortex, color, &instdata);
+ break;
+ case PFIELD_GUIDE:
+ if (cu && (cu->flag & CU_PATH) && ob->runtime.curve_cache->path &&
+ ob->runtime.curve_cache->path->data) {
+ instdata.size_x = instdata.size_y = instdata.size_z = pd->f_strength;
+ float pos[3], tmp[3];
+ where_on_path(ob, 0.0f, pos, tmp, NULL, NULL, NULL);
+ copy_v3_v3(instdata.pos, ob->obmat[3]);
+ translate_m4(instdata.mat, pos[0], pos[1], pos[2]);
+ DRW_buffer_add_entry(cb->field_curve, color, &instdata);
+
+ where_on_path(ob, 1.0f, pos, tmp, NULL, NULL, NULL);
+ copy_v3_v3(instdata.pos, ob->obmat[3]);
+ translate_m4(instdata.mat, pos[0], pos[1], pos[2]);
+ DRW_buffer_add_entry(cb->field_sphere_limit, color, &instdata);
+ /* Restore */
+ copy_v3_v3(instdata.pos, ob->obmat[3]);
+ }
+ break;
+ }
+
+ if (pd->falloff == PFIELD_FALL_TUBE) {
+ if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
+ instdata.size_z = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
+ instdata.size_x = (pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f;
+ instdata.size_y = instdata.size_x;
+ DRW_buffer_add_entry(cb->field_tube_limit, color, &instdata);
+ }
+ if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
+ instdata.size_z = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
+ instdata.size_x = (pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f;
+ instdata.size_y = instdata.size_x;
+ DRW_buffer_add_entry(cb->field_tube_limit, color, &instdata);
+ }
+ }
+ else if (pd->falloff == PFIELD_FALL_CONE) {
+ if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
+ float radius = DEG2RADF((pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f);
+ float distance = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
+ instdata.size_x = distance * sinf(radius);
+ instdata.size_z = distance * cosf(radius);
+ instdata.size_y = instdata.size_x;
+ DRW_buffer_add_entry(cb->field_cone_limit, color, &instdata);
+ }
+ if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
+ float radius = DEG2RADF((pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f);
+ float distance = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
+ instdata.size_x = distance * sinf(radius);
+ instdata.size_z = distance * cosf(radius);
+ instdata.size_y = instdata.size_x;
+ DRW_buffer_add_entry(cb->field_cone_limit, color, &instdata);
+ }
+ }
+ else if (pd->falloff == PFIELD_FALL_SPHERE) {
+ if (pd->flag & PFIELD_USEMAX) {
+ instdata.size_x = instdata.size_y = instdata.size_z = pd->maxdist;
+ DRW_buffer_add_entry(cb->field_sphere_limit, color, &instdata);
+ }
+ if (pd->flag & PFIELD_USEMIN) {
+ instdata.size_x = instdata.size_y = instdata.size_z = pd->mindist;
+ DRW_buffer_add_entry(cb->field_sphere_limit, color, &instdata);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lights
+ * \{ */
+
+void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+
+ Light *la = ob->data;
+ float *color_p;
+ DRW_object_wire_theme_get(ob, view_layer, &color_p);
+ /* Remove the alpha. */
+ float color[4] = {color_p[0], color_p[1], color_p[2], 1.0f};
+ /* Pack render data into object matrix. */
+ union {
+ float mat[4][4];
+ struct {
+ float _pad00[3];
+ union {
+ float area_size_x;
+ float spot_cosine;
+ };
+ float _pad01[3];
+ union {
+ float area_size_y;
+ float spot_blend;
+ };
+ float _pad02[3], clip_sta;
+ float pos[3], clip_end;
+ };
+ } instdata;
+
+ copy_m4_m4(instdata.mat, ob->obmat);
+ /* FIXME / TODO: clipend has no meaning nowadays.
+ * In EEVEE, Only clipsta is used shadowmaping.
+ * Clip end is computed automatically based on light power. */
+ instdata.clip_end = la->clipend;
+ instdata.clip_sta = la->clipsta;
+
+ DRW_buffer_add_entry(cb->groundline, instdata.pos);
+
+ if (la->type == LA_LOCAL) {
+ instdata.area_size_x = instdata.area_size_y = la->area_size;
+ DRW_buffer_add_entry(cb->light_point, color, &instdata);
+ }
+ else if (la->type == LA_SUN) {
+ DRW_buffer_add_entry(cb->light_sun, color, &instdata);
+ }
+ else if (la->type == LA_SPOT) {
+ /* For cycles and eevee the spot attenuation is
+ * y = (1/(1 + x^2) - a)/((1 - a) b)
+ * We solve the case where spot attenuation y = 1 and y = 0
+ * root for y = 1 is (-1 - c) / c
+ * root for y = 0 is (1 - a) / a
+ * and use that to position the blend circle. */
+ float a = cosf(la->spotsize * 0.5f);
+ float b = la->spotblend;
+ float c = a * b - a - b;
+ /* Optimized version or root1 / root0 */
+ instdata.spot_blend = sqrtf((-a - c * a) / (c - c * a));
+ instdata.spot_cosine = a;
+ /* HACK: We pack the area size in alpha color. This is decoded by the shader. */
+ color[3] = -max_ff(la->area_size, FLT_MIN);
+ DRW_buffer_add_entry(cb->light_spot, color, &instdata);
+
+ if ((la->mode & LA_SHOW_CONE) && !DRW_state_is_select()) {
+ float color_inside[4] = {0.0f, 0.0f, 0.0f, 0.5f};
+ float color_outside[4] = {1.0f, 1.0f, 1.0f, 0.3f};
+ DRW_buffer_add_entry(cb->light_spot_cone_front, color_inside, &instdata);
+ DRW_buffer_add_entry(cb->light_spot_cone_back, color_outside, &instdata);
+ }
+ }
+ else if (la->type == LA_AREA) {
+ bool uniform_scale = !ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE);
+ int sqr = ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_RECT);
+ instdata.area_size_x = la->area_size;
+ instdata.area_size_y = uniform_scale ? la->area_size : la->area_sizey;
+ DRW_buffer_add_entry(cb->light_area[sqr], color, &instdata);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lightprobe
+ * \{ */
+
+void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ float *color_p;
+ DRW_object_wire_theme_get(ob, view_layer, &color_p);
+ const LightProbe *prb = (LightProbe *)ob->data;
+ const bool show_clipping = (prb->flag & LIGHTPROBE_FLAG_SHOW_CLIP_DIST) != 0;
+ const bool show_parallax = (prb->flag & LIGHTPROBE_FLAG_SHOW_PARALLAX) != 0;
+ const bool show_influence = (prb->flag & LIGHTPROBE_FLAG_SHOW_INFLUENCE) != 0;
+
+ union {
+ float mat[4][4];
+ struct {
+ float _pad00[4];
+ float _pad01[4];
+ float _pad02[3], clip_sta;
+ float pos[3], clip_end;
+ };
+ } instdata;
+
+ copy_m4_m4(instdata.mat, ob->obmat);
+
+ switch (prb->type) {
+ case LIGHTPROBE_TYPE_CUBE:
+ instdata.clip_sta = show_clipping ? prb->clipsta : -1.0;
+ instdata.clip_end = show_clipping ? prb->clipend : -1.0;
+ DRW_buffer_add_entry(cb->probe_grid, color_p, &instdata);
+ DRW_buffer_add_entry(cb->groundline, instdata.pos);
+
+ if (show_influence) {
+ char shape = (prb->attenuation_type == LIGHTPROBE_SHAPE_BOX) ? OB_CUBE : OB_EMPTY_SPHERE;
+ float f = 1.0f - prb->falloff;
+ OVERLAY_empty_shape(cb, ob->obmat, prb->distinf, shape, color_p);
+ OVERLAY_empty_shape(cb, ob->obmat, prb->distinf * f, shape, color_p);
+ }
+
+ if (show_parallax) {
+ char shape = (prb->parallax_type == LIGHTPROBE_SHAPE_BOX) ? OB_CUBE : OB_EMPTY_SPHERE;
+ float dist = ((prb->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) ? prb->distpar :
+ prb->distinf;
+ OVERLAY_empty_shape(cb, ob->obmat, dist, shape, color_p);
+ }
+ break;
+ case LIGHTPROBE_TYPE_GRID:
+ instdata.clip_sta = show_clipping ? prb->clipsta : -1.0;
+ instdata.clip_end = show_clipping ? prb->clipend : -1.0;
+ DRW_buffer_add_entry(cb->probe_grid, color_p, &instdata);
+
+ if (show_influence) {
+ float f = 1.0f - prb->falloff;
+ OVERLAY_empty_shape(cb, ob->obmat, 1.0 + prb->distinf, OB_CUBE, color_p);
+ OVERLAY_empty_shape(cb, ob->obmat, 1.0 + prb->distinf * f, OB_CUBE, color_p);
+ }
+ break;
+ case LIGHTPROBE_TYPE_PLANAR:
+ DRW_buffer_add_entry(cb->probe_planar, color_p, &instdata);
+
+ if (show_influence) {
+ normalize_v3_length(instdata.mat[2], prb->distinf);
+ DRW_buffer_add_entry(cb->empty_cube, color_p, &instdata);
+ mul_v3_fl(instdata.mat[2], 1.0f - prb->falloff);
+ DRW_buffer_add_entry(cb->empty_cube, color_p, &instdata);
+ }
+ zero_v3(instdata.mat[2]);
+ DRW_buffer_add_entry(cb->empty_cube, color_p, &instdata);
+
+ normalize_m4_m4(instdata.mat, ob->obmat);
+ OVERLAY_empty_shape(cb, instdata.mat, ob->empty_drawsize, OB_SINGLE_ARROW, color_p);
+ break;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Speaker
+ * \{ */
+
+void OVERLAY_speaker_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ float *color_p;
+ DRW_object_wire_theme_get(ob, view_layer, &color_p);
+
+ DRW_buffer_add_entry(cb->speaker, color_p, ob->obmat);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Camera
+ * \{ */
+
+typedef union OVERLAY_CameraInstanceData {
+ /* Pack render data into object matrix and object color. */
+ struct {
+ float color[4];
+ float mat[4][4];
+ };
+ struct {
+ float _pad0[2];
+ float volume_sta;
+ union {
+ float depth;
+ float focus;
+ float volume_end;
+ };
+ float _pad00[3];
+ union {
+ float corner_x;
+ float dist_color_id;
+ };
+ float _pad01[3];
+ union {
+ float corner_y;
+ };
+ float _pad02[3];
+ union {
+ float center_x;
+ float clip_sta;
+ float mist_sta;
+ };
+ float pos[3];
+ union {
+ float center_y;
+ float clip_end;
+ float mist_end;
+ };
+ };
+} OVERLAY_CameraInstanceData;
+
+static void camera_view3d_reconstruction(OVERLAY_ExtraCallBuffers *cb,
+ Scene *scene,
+ View3D *v3d,
+ Object *camera_object,
+ Object *ob,
+ const float color[4])
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool is_select = DRW_state_is_select();
+ const Object *orig_camera_object = DEG_get_original_object(camera_object);
+
+ MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
+ if (clip == NULL) {
+ return;
+ }
+
+ const bool is_solid_bundle = (v3d->bundle_drawtype == OB_EMPTY_SPHERE) &&
+ ((v3d->shading.type != OB_SOLID) || !XRAY_FLAG_ENABLED(v3d));
+
+ MovieTracking *tracking = &clip->tracking;
+ /* Index must start in 1, to mimic BKE_tracking_track_get_indexed. */
+ int track_index = 1;
+
+ uchar text_color_selected[4], text_color_unselected[4];
+ float bundle_color_unselected[4], bundle_color_solid[4];
+
+ UI_GetThemeColor4ubv(TH_SELECT, text_color_selected);
+ UI_GetThemeColor4ubv(TH_TEXT, text_color_unselected);
+ UI_GetThemeColor4fv(TH_WIRE, bundle_color_unselected);
+ UI_GetThemeColor4fv(TH_BUNDLE_SOLID, bundle_color_solid);
+
+ float camera_mat[4][4], normal_mat[4][4];
+ BKE_tracking_get_camera_object_matrix(scene, ob, camera_mat);
+
+ normalize_m4_m4(normal_mat, ob->obmat);
+
+ LISTBASE_FOREACH (MovieTrackingObject *, tracking_object, &tracking->objects) {
+ float tracking_object_mat[4][4];
+
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ copy_m4_m4(tracking_object_mat, camera_mat);
+ }
+ else {
+ const int framenr = BKE_movieclip_remap_scene_to_clip_frame(
+ clip, DEG_get_ctime(draw_ctx->depsgraph));
+ float object_mat[4][4];
+ BKE_tracking_camera_get_reconstructed_interpolate(
+ tracking, tracking_object, framenr, object_mat);
+
+ invert_m4(object_mat);
+ mul_m4_m4m4(tracking_object_mat, normal_mat, object_mat);
+ }
+
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+ for (MovieTrackingTrack *track = tracksbase->first; track; track = track->next) {
+ if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
+ continue;
+ }
+ bool is_selected = TRACK_SELECTED(track);
+
+ float bundle_mat[4][4];
+ copy_m4_m4(bundle_mat, tracking_object_mat);
+ translate_m4(bundle_mat, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
+
+ const float *bundle_color;
+ if (track->flag & TRACK_CUSTOMCOLOR) {
+ bundle_color = track->color;
+ }
+ else if (is_solid_bundle) {
+ bundle_color = bundle_color_solid;
+ }
+ else if (is_selected) {
+ bundle_color = color;
+ }
+ else {
+ bundle_color = bundle_color_unselected;
+ }
+
+ if (is_select) {
+ DRW_select_load_id(orig_camera_object->runtime.select_id | (track_index << 16));
+ track_index++;
+ }
+
+ if (is_solid_bundle) {
+ if (is_selected) {
+ OVERLAY_empty_shape(cb, bundle_mat, v3d->bundle_size, v3d->bundle_drawtype, color);
+ }
+
+ const float bundle_color_v4[4] = {
+ bundle_color[0],
+ bundle_color[1],
+ bundle_color[2],
+ 1.0f,
+ };
+
+ bundle_mat[3][3] = v3d->bundle_size; /* See shader. */
+ DRW_buffer_add_entry(cb->empty_sphere_solid, bundle_color_v4, bundle_mat);
+ }
+ else {
+ OVERLAY_empty_shape(cb, bundle_mat, v3d->bundle_size, v3d->bundle_drawtype, bundle_color);
+ }
+
+ if ((v3d->flag2 & V3D_SHOW_BUNDLENAME) && !is_select) {
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+
+ DRW_text_cache_add(dt,
+ bundle_mat[3],
+ track->name,
+ strlen(track->name),
+ 10,
+ 0,
+ DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+ is_selected ? text_color_selected : text_color_unselected);
+ }
+ }
+
+ if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA) &&
+ !is_select) {
+ MovieTrackingReconstruction *reconstruction;
+ reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
+
+ if (reconstruction->camnr) {
+ MovieReconstructedCamera *camera = reconstruction->cameras;
+ float v0[3], v1[3];
+ for (int a = 0; a < reconstruction->camnr; a++, camera++) {
+ copy_v3_v3(v0, v1);
+ copy_v3_v3(v1, camera->mat[3]);
+ mul_m4_v3(camera_mat, v1);
+ if (a > 0) {
+ /* This one is suboptimal (gl_lines instead of gl_line_strip)
+ * but we keep this for simplicity */
+ OVERLAY_extra_line(cb, v0, v1, TH_CAMERA_PATH);
+ }
+ }
+ }
+ }
+ }
+}
+
+static float camera_offaxis_shiftx_get(Scene *scene,
+ Object *ob,
+ const OVERLAY_CameraInstanceData *instdata,
+ bool right_eye)
+{
+ Camera *cam = ob->data;
+ if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
+ const char *viewnames[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ const float shiftx = BKE_camera_multiview_shift_x(&scene->r, ob, viewnames[right_eye]);
+ const float delta_shiftx = shiftx - cam->shiftx;
+ const float width = instdata->corner_x * 2.0f;
+ return delta_shiftx * width;
+ }
+ else {
+ return 0.0;
+ }
+}
+/**
+ * Draw the stereo 3d support elements (cameras, plane, volume).
+ * They are only visible when not looking through the camera:
+ */
+static void camera_stereoscopy_extra(OVERLAY_ExtraCallBuffers *cb,
+ Scene *scene,
+ View3D *v3d,
+ Object *ob,
+ const OVERLAY_CameraInstanceData *instdata)
+{
+ OVERLAY_CameraInstanceData stereodata = *instdata;
+ Camera *cam = ob->data;
+ const bool is_select = DRW_state_is_select();
+ const char *viewnames[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+
+ const bool is_stereo3d_cameras = (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS) != 0;
+ const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) != 0;
+ const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME) != 0;
+
+ for (int eye = 0; eye < 2; eye++) {
+ ob = BKE_camera_multiview_render(scene, ob, viewnames[eye]);
+ BKE_camera_multiview_model_matrix(&scene->r, ob, viewnames[eye], stereodata.mat);
+
+ stereodata.corner_x = instdata->corner_x;
+ stereodata.corner_y = instdata->corner_y;
+ stereodata.center_x = instdata->center_x + camera_offaxis_shiftx_get(scene, ob, instdata, eye);
+ stereodata.center_y = instdata->center_y;
+ stereodata.depth = instdata->depth;
+
+ if (is_stereo3d_cameras) {
+ DRW_buffer_add_entry_struct(cb->camera_frame, &stereodata);
+
+ /* Connecting line between cameras. */
+ OVERLAY_extra_line_dashed(cb, stereodata.pos, instdata->pos, G_draw.block.colorWire);
+ }
+
+ if (is_stereo3d_volume && !is_select) {
+ float r = (eye == 1) ? 2.0f : 1.0f;
+
+ stereodata.volume_sta = -cam->clip_start;
+ stereodata.volume_end = -cam->clip_end;
+ /* Encode eye + intensity and alpha (see shader) */
+ copy_v2_fl2(stereodata.color, r + 0.15f, 1.0f);
+ DRW_buffer_add_entry_struct(cb->camera_volume_frame, &stereodata);
+
+ if (v3d->stereo3d_volume_alpha > 0.0f) {
+ /* Encode eye + intensity and alpha (see shader) */
+ copy_v2_fl2(stereodata.color, r + 0.999f, v3d->stereo3d_volume_alpha);
+ DRW_buffer_add_entry_struct(cb->camera_volume, &stereodata);
+ }
+ /* restore */
+ copy_v3_v3(stereodata.color, instdata->color);
+ }
+ }
+
+ if (is_stereo3d_plane && !is_select) {
+ if (cam->stereo.convergence_mode == CAM_S3D_TOE) {
+ /* There is no real convergence plane but we highlight the center
+ * point where the views are pointing at. */
+ // zero_v3(stereodata.mat[0]); /* We reconstruct from Z and Y */
+ // zero_v3(stereodata.mat[1]); /* Y doesn't change */
+ zero_v3(stereodata.mat[2]);
+ zero_v3(stereodata.mat[3]);
+ for (int i = 0; i < 2; i++) {
+ float mat[4][4];
+ /* Need normalized version here. */
+ BKE_camera_multiview_model_matrix(&scene->r, ob, viewnames[i], mat);
+ add_v3_v3(stereodata.mat[2], mat[2]);
+ madd_v3_v3fl(stereodata.mat[3], mat[3], 0.5f);
+ }
+ normalize_v3(stereodata.mat[2]);
+ cross_v3_v3v3(stereodata.mat[0], stereodata.mat[1], stereodata.mat[2]);
+ }
+ else if (cam->stereo.convergence_mode == CAM_S3D_PARALLEL) {
+ /* Show plane at the given distance between the views even if it makes no sense. */
+ zero_v3(stereodata.pos);
+ for (int i = 0; i < 2; i++) {
+ float mat[4][4];
+ BKE_camera_multiview_model_matrix_scaled(&scene->r, ob, viewnames[i], mat);
+ madd_v3_v3fl(stereodata.pos, mat[3], 0.5f);
+ }
+ }
+ else if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
+ /* Nothing to do. Everything is already setup. */
+ }
+ stereodata.volume_sta = -cam->stereo.convergence_distance;
+ stereodata.volume_end = -cam->stereo.convergence_distance;
+ /* Encode eye + intensity and alpha (see shader) */
+ copy_v2_fl2(stereodata.color, 0.1f, 1.0f);
+ DRW_buffer_add_entry_struct(cb->camera_volume_frame, &stereodata);
+
+ if (v3d->stereo3d_convergence_alpha > 0.0f) {
+ /* Encode eye + intensity and alpha (see shader) */
+ copy_v2_fl2(stereodata.color, 0.0f, v3d->stereo3d_convergence_alpha);
+ DRW_buffer_add_entry_struct(cb->camera_volume, &stereodata);
+ }
+ }
+}
+
+void OVERLAY_camera_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ OVERLAY_CameraInstanceData instdata;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+
+ Camera *cam = ob->data;
+ Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera);
+ const bool is_select = DRW_state_is_select();
+ const bool is_active = (ob == camera_object);
+ const bool look_through = (is_active && (rv3d->persp == RV3D_CAMOB));
+
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+ const bool is_stereo3d_view = (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
+ const bool is_stereo3d_display_extra = is_active && is_multiview && (!look_through) &&
+ ((v3d->stereo3d_flag) != 0);
+ const bool is_selection_camera_stereo = is_select && look_through && is_multiview &&
+ is_stereo3d_view;
+
+ float vec[4][3], asp[2], shift[2], scale[3], drawsize, center[2], corner[2];
+
+ float *color_p;
+ DRW_object_wire_theme_get(ob, view_layer, &color_p);
+ copy_v4_v4(instdata.color, color_p);
+
+ normalize_m4_m4(instdata.mat, ob->obmat);
+
+ /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here. */
+ if (is_selection_camera_stereo) {
+ copy_v3_fl(scale, 1.0f);
+ }
+ else {
+ copy_v3_fl3(scale, len_v3(ob->obmat[0]), len_v3(ob->obmat[1]), len_v3(ob->obmat[2]));
+ invert_v3(scale);
+ }
+
+ BKE_camera_view_frame_ex(
+ scene, cam, cam->drawsize, look_through, scale, asp, shift, &drawsize, vec);
+
+ /* Apply scale to simplify the rest of the drawing. */
+ invert_v3(scale);
+ for (int i = 0; i < 4; i++) {
+ mul_v3_v3(vec[i], scale);
+ /* Project to z=-1 plane. Makes positionning / scaling easier. (see shader) */
+ mul_v2_fl(vec[i], 1.0f / fabsf(vec[i][2]));
+ }
+
+ /* Frame coords */
+ mid_v2_v2v2(center, vec[0], vec[2]);
+ sub_v2_v2v2(corner, vec[0], center);
+ instdata.corner_x = corner[0];
+ instdata.corner_y = corner[1];
+ instdata.center_x = center[0];
+ instdata.center_y = center[1];
+ instdata.depth = vec[0][2];
+
+ if (look_through) {
+ if (!DRW_state_is_image_render()) {
+ /* Only draw the frame. */
+ if (is_multiview) {
+ float mat[4][4];
+ const bool is_right = v3d->multiview_eye == STEREO_RIGHT_ID;
+ const char *view_name = is_right ? STEREO_RIGHT_NAME : STEREO_LEFT_NAME;
+ BKE_camera_multiview_model_matrix(&scene->r, ob, view_name, mat);
+ instdata.center_x += camera_offaxis_shiftx_get(scene, ob, &instdata, is_right);
+ for (int i = 0; i < 4; i++) {
+ /* Partial copy to avoid overriding packed data. */
+ copy_v3_v3(instdata.mat[i], mat[i]);
+ }
+ }
+ instdata.depth = -instdata.depth; /* Hides the back of the camera wires (see shader). */
+ DRW_buffer_add_entry_struct(cb->camera_frame, &instdata);
+ }
+ }
+ else {
+ /* Stereo cameras, volumes, plane drawing. */
+ if (is_stereo3d_display_extra) {
+ camera_stereoscopy_extra(cb, scene, v3d, ob, &instdata);
+ }
+ else {
+ DRW_buffer_add_entry_struct(cb->camera_frame, &instdata);
+ }
+ }
+
+ if (!look_through) {
+ /* Triangle. */
+ float tria_size = 0.7f * drawsize / fabsf(instdata.depth);
+ float tria_margin = 0.1f * drawsize / fabsf(instdata.depth);
+ instdata.center_x = center[0];
+ instdata.center_y = center[1] + instdata.corner_y + tria_margin + tria_size;
+ instdata.corner_x = instdata.corner_y = -tria_size;
+ DRW_buffer_add_entry_struct(cb->camera_tria[is_active], &instdata);
+ }
+
+ if (cam->flag & CAM_SHOWLIMITS) {
+ /* Scale focus point. */
+ mul_v3_fl(instdata.mat[0], cam->drawsize);
+ mul_v3_fl(instdata.mat[1], cam->drawsize);
+
+ instdata.dist_color_id = (is_active) ? 3 : 2;
+ instdata.focus = -BKE_camera_object_dof_distance(ob);
+ instdata.clip_sta = cam->clip_start;
+ instdata.clip_end = cam->clip_end;
+ DRW_buffer_add_entry_struct(cb->camera_distances, &instdata);
+ }
+
+ if (cam->flag & CAM_SHOWMIST) {
+ World *world = scene->world;
+ if (world) {
+ instdata.dist_color_id = (is_active) ? 1 : 0;
+ instdata.focus = 1.0f; /* Disable */
+ instdata.mist_sta = world->miststa;
+ instdata.mist_end = world->miststa + world->mistdist;
+ DRW_buffer_add_entry_struct(cb->camera_distances, &instdata);
+ }
+ }
+
+ /* Motion Tracking. */
+ if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) != 0) {
+ camera_view3d_reconstruction(cb, scene, v3d, camera_object, ob, color_p);
+ }
+
+ /* Background images. */
+ if (look_through && (cam->flag & CAM_SHOW_BG_IMAGE) && !BLI_listbase_is_empty(&cam->bg_images)) {
+ OVERLAY_image_camera_cache_populate(vedata, ob);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Relationships & constraints
+ * \{ */
+
+static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob)
+{
+ float *relation_color = G_draw.block.colorWire;
+ float *constraint_color = G_draw.block.colorGridAxisZ; /* ? */
+
+ if (ob->parent && (DRW_object_visibility_in_active_context(ob->parent) & OB_VISIBLE_SELF)) {
+ float *parent_pos = ob->runtime.parent_display_origin;
+ OVERLAY_extra_line_dashed(cb, parent_pos, ob->obmat[3], relation_color);
+ }
+
+ if (ob->rigidbody_constraint) {
+ Object *rbc_ob1 = ob->rigidbody_constraint->ob1;
+ Object *rbc_ob2 = ob->rigidbody_constraint->ob2;
+ if (rbc_ob1 && (DRW_object_visibility_in_active_context(rbc_ob1) & OB_VISIBLE_SELF)) {
+ OVERLAY_extra_line_dashed(cb, rbc_ob1->obmat[3], ob->obmat[3], relation_color);
+ }
+ if (rbc_ob2 && (DRW_object_visibility_in_active_context(rbc_ob2) & OB_VISIBLE_SELF)) {
+ OVERLAY_extra_line_dashed(cb, rbc_ob2->obmat[3], ob->obmat[3], relation_color);
+ }
+ }
+
+ /* Drawing the constraint lines */
+ if (!BLI_listbase_is_empty(&ob->constraints)) {
+ bConstraint *curcon;
+ bConstraintOb *cob;
+ ListBase *list = &ob->constraints;
+
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+
+ for (curcon = list->first; curcon; curcon = curcon->next) {
+ if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_OBJECTSOLVER)) {
+ /* special case for object solver and follow track constraints because they don't fill
+ * constraint targets properly (design limitation -- scene is needed for their target
+ * but it can't be accessed from get_targets callback) */
+ Object *camob = NULL;
+
+ if (curcon->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
+ bFollowTrackConstraint *data = (bFollowTrackConstraint *)curcon->data;
+ camob = data->camera ? data->camera : scene->camera;
+ }
+ else if (curcon->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
+ bObjectSolverConstraint *data = (bObjectSolverConstraint *)curcon->data;
+ camob = data->camera ? data->camera : scene->camera;
+ }
+
+ if (camob) {
+ OVERLAY_extra_line_dashed(cb, camob->obmat[3], ob->obmat[3], constraint_color);
+ }
+ }
+ else {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+
+ if ((cti && cti->get_constraint_targets) && (curcon->flag & CONSTRAINT_EXPAND)) {
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ cti->get_constraint_targets(curcon, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ /* calculate target's matrix */
+ if (cti->get_target_matrix) {
+ cti->get_target_matrix(depsgraph, curcon, cob, ct, DEG_get_ctime(depsgraph));
+ }
+ else {
+ unit_m4(ct->matrix);
+ }
+ OVERLAY_extra_line_dashed(cb, ct->matrix[3], ob->obmat[3], constraint_color);
+ }
+
+ if (cti->flush_constraint_targets) {
+ cti->flush_constraint_targets(curcon, &targets, 1);
+ }
+ }
+ }
+ }
+ BKE_constraints_clear_evalob(cob);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name GPencil.
+ * \{ */
+
+static void OVERLAY_gpencil_color_names(Object *ob)
+{
+ if (ob->mode != OB_MODE_EDIT_GPENCIL) {
+ return;
+ }
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if (gpd == NULL) {
+ return;
+ }
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ uchar color[4];
+ UI_GetThemeColor4ubv(theme_id, color);
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->flag & GP_LAYER_HIDE) {
+ continue;
+ }
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL) {
+ continue;
+ }
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ Material *ma = give_current_material(ob, gps->mat_nr + 1);
+ if (ma == NULL) {
+ continue;
+ }
+
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ /* skip stroke if it doesn't have any valid data */
+ if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) {
+ continue;
+ }
+ /* check if the color is visible */
+ if (gp_style->flag & GP_STYLE_COLOR_HIDE) {
+ continue;
+ }
+
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ float fpt[3];
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ if (pt->flag & GP_SPOINT_SELECT) {
+ mul_v3_m4v3(fpt, ob->obmat, &pt->x);
+ DRW_text_cache_add(dt,
+ fpt,
+ ma->id.name + 2,
+ strlen(ma->id.name + 2),
+ 10,
+ 0,
+ DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+ color);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void OVERLAY_gpencil_cache_populate(OVERLAY_Data *UNUSED(vedata), Object *ob)
+{
+ /* don't show object extras in set's */
+ if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
+ if ((ob->dtx & OB_DRAWNAME) && DRW_state_show_text()) {
+ OVERLAY_gpencil_color_names(ob);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Volumetric / Smoke sim
+ * \{ */
+
+static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb,
+ OVERLAY_Data *data,
+ Object *ob,
+ ModifierData *md,
+ Scene *scene,
+ float *color)
+{
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ SmokeDomainSettings *sds = smd->domain;
+
+ /* Don't show smoke before simulation starts, this could be made an option in the future. */
+ const bool draw_velocity = (sds->draw_velocity && sds->fluid &&
+ CFRA >= sds->point_cache[0]->startframe);
+
+ /* Small cube showing voxel size. */
+ {
+ float min[3];
+ madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min);
+ float voxel_cubemat[4][4] = {{0.0f}};
+ /* scale small cube to voxel size */
+ voxel_cubemat[0][0] = 1.0f / (float)sds->base_res[0];
+ voxel_cubemat[1][1] = 1.0f / (float)sds->base_res[1];
+ voxel_cubemat[2][2] = 1.0f / (float)sds->base_res[2];
+ voxel_cubemat[3][3] = 1.0f;
+ /* translate small cube to corner */
+ copy_v3_v3(voxel_cubemat[3], min);
+ /* move small cube into the domain (otherwise its centered on vertex of domain object) */
+ translate_m4(voxel_cubemat, 1.0f, 1.0f, 1.0f);
+ mul_m4_m4m4(voxel_cubemat, ob->obmat, voxel_cubemat);
+
+ DRW_buffer_add_entry(cb->empty_cube, color, voxel_cubemat);
+ }
+
+ if (draw_velocity) {
+ const bool use_needle = (sds->vector_draw_type == VECTOR_DRAW_NEEDLE);
+ int line_count = (use_needle) ? 6 : 1;
+ int slice_axis = -1;
+ line_count *= sds->res[0] * sds->res[1] * sds->res[2];
+
+ if (sds->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED &&
+ sds->axis_slice_method == AXIS_SLICE_SINGLE) {
+ float viewinv[4][4];
+ DRW_view_viewmat_get(NULL, viewinv, true);
+
+ const int axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewinv[2]) :
+ sds->slice_axis - 1;
+ slice_axis = axis;
+ line_count /= sds->res[axis];
+ }
+
+ GPU_create_smoke_velocity(smd);
+
+ GPUShader *sh = OVERLAY_shader_volume_velocity(use_needle);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, data->psl->extra_ps[0]);
+ DRW_shgroup_uniform_texture(grp, "velocityX", sds->tex_velocity_x);
+ DRW_shgroup_uniform_texture(grp, "velocityY", sds->tex_velocity_y);
+ DRW_shgroup_uniform_texture(grp, "velocityZ", sds->tex_velocity_z);
+ DRW_shgroup_uniform_float_copy(grp, "displaySize", sds->vector_scale);
+ DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth);
+ DRW_shgroup_uniform_vec3_copy(grp, "cellSize", sds->cell_size);
+ DRW_shgroup_uniform_vec3_copy(grp, "domainOriginOffset", sds->p0);
+ DRW_shgroup_uniform_ivec3_copy(grp, "adaptiveCellOffset", sds->res_min);
+ DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis);
+ DRW_shgroup_call_procedural_lines(grp, ob, line_count);
+
+ BLI_addtail(&data->stl->pd->smoke_domains, BLI_genericNodeN(smd));
+ }
+}
+
+static void OVERLAY_volume_free_smoke_textures(OVERLAY_Data *data)
+{
+ /* Free Smoke Textures after rendering */
+ /* XXX This is a waste of processing and GPU bandwidth if nothing
+ * is updated. But the problem is since Textures are stored in the
+ * modifier we don't want them to take precious VRAM if the
+ * modifier is not used for display. We should share them for
+ * all viewport in a redraw at least. */
+ LinkData *link;
+ while ((link = BLI_pophead(&data->stl->pd->smoke_domains))) {
+ SmokeModifierData *smd = (SmokeModifierData *)link->data;
+ GPU_free_smoke_velocity(smd);
+ MEM_freeN(link);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+static void OVERLAY_object_center(OVERLAY_ExtraCallBuffers *cb,
+ Object *ob,
+ OVERLAY_PrivateData *pd,
+ ViewLayer *view_layer)
+{
+ const bool is_library = ob->id.us > 1 || ID_IS_LINKED(ob);
+
+ if (ob == OBACT(view_layer)) {
+ DRW_buffer_add_entry(cb->center_active, ob->obmat[3]);
+ }
+ else if (ob->base_flag & BASE_SELECTED) {
+ DRWCallBuffer *cbuf = (is_library) ? cb->center_selected_lib : cb->center_selected;
+ DRW_buffer_add_entry(cbuf, ob->obmat[3]);
+ }
+ else if (pd->v3d_flag & V3D_DRAW_CENTERS) {
+ DRWCallBuffer *cbuf = (is_library) ? cb->center_deselected_lib : cb->center_deselected;
+ DRW_buffer_add_entry(cbuf, ob->obmat[3]);
+ }
+}
+
+static void OVERLAY_object_name(Object *ob, int theme_id)
+{
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ uchar color[4];
+ UI_GetThemeColor4ubv(theme_id, color);
+
+ DRW_text_cache_add(dt,
+ ob->obmat[3],
+ ob->id.name + 2,
+ strlen(ob->id.name + 2),
+ 10,
+ 0,
+ DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+ color);
+}
+
+void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ Scene *scene = draw_ctx->scene;
+ ModifierData *md = NULL;
+
+ const bool is_select_mode = DRW_state_is_select();
+ const bool is_paint_mode = (draw_ctx->object_mode &
+ (OB_MODE_ALL_PAINT | OB_MODE_ALL_PAINT_GPENCIL)) != 0;
+ const bool from_dupli = (ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) != 0;
+ const bool has_bounds = !ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_EMPTY, OB_SPEAKER, OB_LIGHTPROBE);
+ const bool has_texspace = has_bounds &&
+ !ELEM(ob->type, OB_EMPTY, OB_LATTICE, OB_ARMATURE, OB_GPENCIL);
+
+ const bool draw_relations = ((pd->v3d_flag & V3D_HIDE_HELPLINES) == 0) && !is_select_mode;
+ const bool draw_obcenters = !is_paint_mode &&
+ (pd->overlay.flag & V3D_OVERLAY_HIDE_OBJECT_ORIGINS) == 0;
+ const bool draw_texspace = (ob->dtx & OB_TEXSPACE) && has_texspace;
+ const bool draw_obname = (ob->dtx & OB_DRAWNAME) && DRW_state_show_text();
+ const bool draw_bounds = has_bounds && ((ob->dt == OB_BOUNDBOX) ||
+ ((ob->dtx & OB_DRAWBOUNDOX) && !from_dupli));
+ const bool draw_xform = draw_ctx->object_mode == OB_MODE_OBJECT &&
+ (scene->toolsettings->transform_flag & SCE_XFORM_DATA_ORIGIN) &&
+ (ob->base_flag & BASE_SELECTED) && !is_select_mode;
+ const bool draw_volume = !from_dupli && (md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ (modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
+ (((SmokeModifierData *)md)->domain != NULL);
+
+ float *color;
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ if (ob->pd && ob->pd->forcefield) {
+ OVERLAY_forcefield(cb, ob, view_layer);
+ }
+
+ if (draw_bounds) {
+ OVERLAY_bounds(cb, ob, theme_id, ob->boundtype, false);
+ }
+ /* Helpers for when we're transforming origins. */
+ if (draw_xform) {
+ float color_xform[4] = {0.75f, 0.75f, 0.75f, 0.5f};
+ DRW_buffer_add_entry(cb->origin_xform, color_xform, ob->obmat);
+ }
+ /* don't show object extras in set's */
+ if (!from_dupli) {
+ if (draw_obcenters) {
+ OVERLAY_object_center(cb, ob, pd, view_layer);
+ }
+ if (draw_relations) {
+ OVERLAY_relationship_lines(cb, draw_ctx->depsgraph, draw_ctx->scene, ob);
+ }
+ if (draw_obname) {
+ OVERLAY_object_name(ob, theme_id);
+ }
+ if (draw_texspace) {
+ OVERLAY_texture_space(cb, ob, theme_id);
+ }
+ if (ob->rigidbody_object != NULL) {
+ OVERLAY_collision(cb, ob, theme_id);
+ }
+ if (ob->dtx & OB_AXIS) {
+ DRW_buffer_add_entry(cb->empty_axes, color, ob->obmat);
+ }
+ if (draw_volume) {
+ OVERLAY_volume_extra(cb, vedata, ob, md, scene, color);
+ }
+ }
+}
+
+void OVERLAY_extra_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->extra_blend_ps);
+
+ if (pd->antialiasing.enabled) {
+ GPU_framebuffer_bind(fbl->overlay_line_fb);
+ }
+
+ DRW_draw_pass(psl->extra_ps[0]);
+
+ if (pd->antialiasing.enabled) {
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+}
+
+void OVERLAY_extra_in_front_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->extra_ps[1]);
+
+ OVERLAY_volume_free_smoke_textures(vedata);
+}
+
+void OVERLAY_extra_centers_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->extra_centers_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_facing.c b/source/blender/draw/engines/overlay/overlay_facing.c
new file mode 100644
index 00000000000..a69d7537637
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_facing.c
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_facing_init(OVERLAY_Data *UNUSED(vedata))
+{
+}
+
+void OVERLAY_facing_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->facing_ps, state | pd->clipping_state);
+
+ GPUShader *sh = OVERLAY_shader_facing();
+ pd->facing_grp = DRW_shgroup_create(sh, psl->facing_ps);
+}
+
+void OVERLAY_facing_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ DRW_shgroup_call(pd->facing_grp, geom, ob);
+ }
+}
+
+void OVERLAY_facing_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ /* We need to match underlying geometry pass, at the cost of bypassing TAA. */
+ DRW_view_set_active(NULL);
+
+ DRW_draw_pass(psl->facing_ps);
+
+ DRW_view_set_active(pd->view_default);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_grid.c b/source/blender/draw/engines/overlay/overlay_grid.c
new file mode 100644
index 00000000000..7dea6c198d0
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_grid.c
@@ -0,0 +1,220 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_camera_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_view3d.h"
+
+#include "overlay_private.h"
+
+enum {
+ SHOW_AXIS_X = (1 << 0),
+ SHOW_AXIS_Y = (1 << 1),
+ SHOW_AXIS_Z = (1 << 2),
+ SHOW_GRID = (1 << 3),
+ PLANE_XY = (1 << 4),
+ PLANE_XZ = (1 << 5),
+ PLANE_YZ = (1 << 6),
+ CLIP_ZPOS = (1 << 7),
+ CLIP_ZNEG = (1 << 8),
+ GRID_BACK = (1 << 9),
+};
+
+void OVERLAY_grid_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ OVERLAY_ShadingData *shd = &pd->shdata;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+
+ const bool show_axis_x = (pd->v3d_gridflag & V3D_SHOW_X) != 0;
+ const bool show_axis_y = (pd->v3d_gridflag & V3D_SHOW_Y) != 0;
+ const bool show_axis_z = (pd->v3d_gridflag & V3D_SHOW_Z) != 0;
+ const bool show_floor = (pd->v3d_gridflag & V3D_SHOW_FLOOR) != 0;
+ const bool show_ortho_grid = (pd->v3d_gridflag & V3D_SHOW_ORTHO_GRID) != 0;
+
+ shd->grid_flag = 0;
+
+ if (pd->hide_overlays || !(show_axis_y || show_axis_z || show_floor || show_ortho_grid)) {
+ return;
+ }
+
+ float viewinv[4][4], wininv[4][4];
+ float viewmat[4][4], winmat[4][4];
+ DRW_view_winmat_get(NULL, winmat, false);
+ DRW_view_winmat_get(NULL, wininv, true);
+ DRW_view_viewmat_get(NULL, viewmat, false);
+ DRW_view_viewmat_get(NULL, viewinv, true);
+
+ /* if perps */
+ if (winmat[3][3] == 0.0f || rv3d->view == RV3D_VIEW_USER) {
+ if (show_axis_x) {
+ shd->grid_flag |= PLANE_XY | SHOW_AXIS_X;
+ }
+ if (show_axis_y) {
+ shd->grid_flag |= PLANE_XY | SHOW_AXIS_Y;
+ }
+ if (show_floor) {
+ shd->grid_flag |= PLANE_XY | SHOW_GRID;
+ }
+ }
+ else {
+ if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) {
+ shd->grid_flag = PLANE_YZ | SHOW_AXIS_Y | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK;
+ }
+ else if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
+ shd->grid_flag = PLANE_XY | SHOW_AXIS_X | SHOW_AXIS_Y | SHOW_GRID | GRID_BACK;
+ }
+ else if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
+ shd->grid_flag = PLANE_XZ | SHOW_AXIS_X | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK;
+ }
+ }
+
+ shd->grid_axes[0] = (float)((shd->grid_flag & (PLANE_XZ | PLANE_XY)) != 0);
+ shd->grid_axes[1] = (float)((shd->grid_flag & (PLANE_YZ | PLANE_XY)) != 0);
+ shd->grid_axes[2] = (float)((shd->grid_flag & (PLANE_YZ | PLANE_XZ)) != 0);
+
+ /* Z axis if needed */
+ if (((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) && show_axis_z) {
+ shd->zpos_flag = SHOW_AXIS_Z;
+
+ float zvec[3], campos[3];
+ negate_v3_v3(zvec, viewinv[2]);
+ copy_v3_v3(campos, viewinv[3]);
+
+ /* z axis : chose the most facing plane */
+ if (fabsf(zvec[0]) < fabsf(zvec[1])) {
+ shd->zpos_flag |= PLANE_XZ;
+ }
+ else {
+ shd->zpos_flag |= PLANE_YZ;
+ }
+
+ shd->zneg_flag = shd->zpos_flag;
+
+ /* Persp : If camera is below floor plane, we switch clipping
+ * Ortho : If eye vector is looking up, we switch clipping */
+ if (((winmat[3][3] == 0.0f) && (campos[2] > 0.0f)) ||
+ ((winmat[3][3] != 0.0f) && (zvec[2] < 0.0f))) {
+ shd->zpos_flag |= CLIP_ZPOS;
+ shd->zneg_flag |= CLIP_ZNEG;
+ }
+ else {
+ shd->zpos_flag |= CLIP_ZNEG;
+ shd->zneg_flag |= CLIP_ZPOS;
+ }
+
+ shd->zplane_axes[0] = (float)((shd->zpos_flag & (PLANE_XZ | PLANE_XY)) != 0);
+ shd->zplane_axes[1] = (float)((shd->zpos_flag & (PLANE_YZ | PLANE_XY)) != 0);
+ shd->zplane_axes[2] = (float)((shd->zpos_flag & (PLANE_YZ | PLANE_XZ)) != 0);
+ }
+ else {
+ shd->zneg_flag = shd->zpos_flag = CLIP_ZNEG | CLIP_ZPOS;
+ }
+
+ float dist;
+ if (rv3d->persp == RV3D_CAMOB && v3d->camera && v3d->camera->type == OB_CAMERA) {
+ Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera);
+ dist = ((Camera *)(camera_object->data))->clip_end;
+ }
+ else {
+ dist = v3d->clip_end;
+ }
+
+ if (winmat[3][3] == 0.0f) {
+ shd->grid_mesh_size = dist;
+ }
+ else {
+ float viewdist = 1.0f / min_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1]));
+ shd->grid_mesh_size = viewdist * dist;
+ }
+
+ shd->grid_distance = dist / 2.0f;
+ shd->grid_line_size = max_ff(0.0f, U.pixelsize - 1.0f) * 0.5f;
+
+ ED_view3d_grid_steps(scene, v3d, rv3d, shd->grid_steps);
+}
+
+void OVERLAY_grid_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_ShadingData *shd = &vedata->stl->pd->shdata;
+ OVERLAY_PassList *psl = vedata->psl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ psl->grid_ps = NULL;
+
+ if (shd->grid_flag == 0 || !DRW_state_is_fbo()) {
+ return;
+ }
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->grid_ps, state);
+
+ GPUShader *sh = OVERLAY_shader_grid();
+ struct GPUBatch *geom = DRW_cache_grid_get();
+
+ /* Create 3 quads to render ordered transparency Z axis */
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->grid_ps);
+ DRW_shgroup_uniform_int(grp, "gridFlag", &shd->zneg_flag, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeAxes", shd->zplane_axes, 1);
+ DRW_shgroup_uniform_float(grp, "gridDistance", &shd->grid_distance, 1);
+ DRW_shgroup_uniform_float_copy(grp, "lineKernel", shd->grid_line_size);
+ DRW_shgroup_uniform_float_copy(grp, "meshSize", shd->grid_mesh_size);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_call(grp, geom, NULL);
+
+ grp = DRW_shgroup_create(sh, psl->grid_ps);
+ DRW_shgroup_uniform_int(grp, "gridFlag", &shd->grid_flag, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeAxes", shd->grid_axes, 1);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_uniform_float(grp, "gridSteps", shd->grid_steps, ARRAY_SIZE(shd->grid_steps));
+ DRW_shgroup_call(grp, geom, NULL);
+
+ grp = DRW_shgroup_create(sh, psl->grid_ps);
+ DRW_shgroup_uniform_int(grp, "gridFlag", &shd->zpos_flag, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeAxes", shd->zplane_axes, 1);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_call(grp, geom, NULL);
+}
+
+void OVERLAY_grid_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+
+ if (psl->grid_ps) {
+ GPU_framebuffer_bind(fbl->overlay_color_only_fb);
+ DRW_draw_pass(psl->grid_ps);
+
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_image.c b/source/blender/draw/engines/overlay/overlay_image.c
new file mode 100644
index 00000000000..1984e3283a9
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_image.c
@@ -0,0 +1,470 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_camera.h"
+#include "BKE_image.h"
+#include "BKE_movieclip.h"
+#include "BKE_object.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_screen_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_view3d.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_image_init(OVERLAY_Data *vedata)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ pd->view_reference_images = DRW_view_create_with_zoffset(
+ pd->view_default, draw_ctx->rv3d, -1.0f);
+}
+
+void OVERLAY_image_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DRWState state;
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_BLEND_ALPHA_UNDER_PREMUL;
+ DRW_PASS_CREATE(psl->image_background_under_ps, state);
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->image_background_over_ps, state);
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
+ DRW_PASS_CREATE(psl->image_empties_ps, state | pd->clipping_state);
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->image_empties_back_ps, state | pd->clipping_state);
+ DRW_PASS_CREATE(psl->image_empties_blend_ps, state | pd->clipping_state);
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->image_empties_front_ps, state);
+ DRW_PASS_CREATE(psl->image_foreground_ps, state);
+}
+
+static void overlay_image_calc_aspect(Image *ima, const int size[2], float r_image_aspect[2])
+{
+ float ima_x, ima_y;
+ if (ima) {
+ ima_x = size[0];
+ ima_y = size[1];
+ }
+ else {
+ /* if no image, make it a 1x1 empty square, honor scale & offset */
+ ima_x = ima_y = 1.0f;
+ }
+ /* Get the image aspect even if the buffer is invalid */
+ float sca_x = 1.0f, sca_y = 1.0f;
+ if (ima) {
+ if (ima->aspx > ima->aspy) {
+ sca_y = ima->aspy / ima->aspx;
+ }
+ else if (ima->aspx < ima->aspy) {
+ sca_x = ima->aspx / ima->aspy;
+ }
+ }
+
+ const float scale_x_inv = ima_x * sca_x;
+ const float scale_y_inv = ima_y * sca_y;
+ if (scale_x_inv > scale_y_inv) {
+ r_image_aspect[0] = 1.0f;
+ r_image_aspect[1] = scale_y_inv / scale_x_inv;
+ }
+ else {
+ r_image_aspect[0] = scale_x_inv / scale_y_inv;
+ r_image_aspect[1] = 1.0f;
+ }
+}
+
+static void camera_background_images_stereo_setup(Scene *scene,
+ View3D *v3d,
+ Image *ima,
+ ImageUser *iuser)
+{
+ if (BKE_image_is_stereo(ima)) {
+ iuser->flag |= IMA_SHOW_STEREO;
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0) {
+ iuser->multiview_eye = STEREO_LEFT_ID;
+ }
+ else if (v3d->stereo3d_camera != STEREO_3D_ID) {
+ /* show only left or right camera */
+ iuser->multiview_eye = v3d->stereo3d_camera;
+ }
+
+ BKE_image_multiview_index(ima, iuser);
+ }
+ else {
+ iuser->flag &= ~IMA_SHOW_STEREO;
+ }
+}
+
+static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgpic,
+ const DRWContextState *draw_ctx,
+ OVERLAY_PrivateData *pd,
+ float *r_aspect,
+ bool *r_use_alpha_premult)
+{
+ Image *image = bgpic->ima;
+ ImageUser *iuser = &bgpic->iuser;
+ MovieClip *clip = NULL;
+ GPUTexture *tex = NULL;
+ Scene *scene = draw_ctx->scene;
+ float aspect_x, aspect_y;
+ int width, height;
+ int ctime = (int)DEG_get_ctime(draw_ctx->depsgraph);
+ *r_use_alpha_premult = false;
+
+ switch (bgpic->source) {
+ case CAM_BGIMG_SOURCE_IMAGE:
+ if (image == NULL) {
+ return NULL;
+ }
+ *r_use_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL);
+
+ BKE_image_user_frame_calc(image, iuser, ctime);
+ if (image->source == IMA_SRC_SEQUENCE && !(iuser->flag & IMA_USER_FRAME_IN_RANGE)) {
+ /* Frame is out of range, dont show. */
+ return NULL;
+ }
+ else {
+ camera_background_images_stereo_setup(scene, draw_ctx->v3d, image, iuser);
+ }
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, NULL);
+ if (ibuf == NULL) {
+ return NULL;
+ }
+
+ tex = GPU_texture_from_blender(image, iuser, GL_TEXTURE_2D);
+ if (tex == NULL) {
+ return NULL;
+ }
+
+ aspect_x = bgpic->ima->aspx;
+ aspect_y = bgpic->ima->aspy;
+
+ width = ibuf->x;
+ height = ibuf->y;
+
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ break;
+
+ case CAM_BGIMG_SOURCE_MOVIE:
+ if (bgpic->flag & CAM_BGIMG_FLAG_CAMERACLIP) {
+ if (scene->camera) {
+ clip = BKE_object_movieclip_get(scene, scene->camera, true);
+ }
+ }
+ else {
+ clip = bgpic->clip;
+ }
+
+ if (clip == NULL) {
+ return NULL;
+ }
+
+ BKE_movieclip_user_set_frame(&bgpic->cuser, ctime);
+ tex = GPU_texture_from_movieclip(clip, &bgpic->cuser, GL_TEXTURE_2D);
+ if (tex == NULL) {
+ return NULL;
+ }
+
+ aspect_x = clip->aspx;
+ aspect_y = clip->aspy;
+
+ BKE_movieclip_get_size(clip, &bgpic->cuser, &width, &height);
+
+ /* Save for freeing. */
+ BLI_addtail(&pd->bg_movie_clips, BLI_genericNodeN(clip));
+ break;
+
+ default:
+ /* Unsupported type. */
+ return NULL;
+ }
+
+ *r_aspect = (width * aspect_x) / (height * aspect_y);
+ return tex;
+}
+
+static void OVERLAY_image_free_movieclips_textures(OVERLAY_Data *data)
+{
+ /* Free Movie clip textures after rendering */
+ LinkData *link;
+ while ((link = BLI_pophead(&data->stl->pd->bg_movie_clips))) {
+ MovieClip *clip = (MovieClip *)link->data;
+ GPU_free_texture_movieclip(clip);
+ MEM_freeN(link);
+ }
+}
+
+static void image_camera_background_matrix_get(const Camera *cam,
+ const CameraBGImage *bgpic,
+ const DRWContextState *draw_ctx,
+ const float image_aspect,
+ float rmat[4][4])
+{
+ float rotate[4][4], scale[4][4], translate[4][4];
+
+ axis_angle_to_mat4_single(rotate, 'Z', -bgpic->rotation);
+ unit_m4(scale);
+ unit_m4(translate);
+
+ /* Normalized Object space camera frame corners. */
+ float cam_corners[4][3];
+ BKE_camera_view_frame(draw_ctx->scene, cam, cam_corners);
+ float cam_width = fabsf(cam_corners[0][0] - cam_corners[3][0]);
+ float cam_height = fabsf(cam_corners[0][1] - cam_corners[1][1]);
+ float cam_aspect = cam_width / cam_height;
+
+ if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) {
+ /* Crop. */
+ if (image_aspect > cam_aspect) {
+ scale[0][0] *= cam_height * image_aspect;
+ scale[1][1] *= cam_height;
+ }
+ else {
+ scale[0][0] *= cam_width;
+ scale[1][1] *= cam_width / image_aspect;
+ }
+ }
+ else if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) {
+ /* Fit. */
+ if (image_aspect > cam_aspect) {
+ scale[0][0] *= cam_width;
+ scale[1][1] *= cam_width / image_aspect;
+ }
+ else {
+ scale[0][0] *= cam_height * image_aspect;
+ scale[1][1] *= cam_height;
+ }
+ }
+ else {
+ /* Stretch. */
+ scale[0][0] *= cam_width;
+ scale[1][1] *= cam_height;
+ }
+
+ translate[3][0] = bgpic->offset[0];
+ translate[3][1] = bgpic->offset[1];
+ translate[3][2] = cam_corners[0][2];
+ /* These lines are for keeping 2.80 behavior and could be removed to keep 2.79 behavior. */
+ translate[3][0] *= min_ff(1.0f, cam_aspect);
+ translate[3][1] /= max_ff(1.0f, cam_aspect) * (image_aspect / cam_aspect);
+ /* quad is -1..1 so divide by 2. */
+ scale[0][0] *= 0.5f * bgpic->scale * ((bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) ? -1.0 : 1.0);
+ scale[1][1] *= 0.5f * bgpic->scale * ((bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) ? -1.0 : 1.0);
+ /* Camera shift. (middle of cam_corners) */
+ translate[3][0] += (cam_corners[0][0] + cam_corners[2][0]) * 0.5f;
+ translate[3][1] += (cam_corners[0][1] + cam_corners[2][1]) * 0.5f;
+
+ mul_m4_series(rmat, translate, rotate, scale);
+}
+
+void OVERLAY_image_camera_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ OVERLAY_PassList *psl = vedata->psl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Camera *cam = ob->data;
+
+ const bool show_frame = BKE_object_empty_image_frame_is_visible_in_view3d(ob, draw_ctx->rv3d);
+
+ if (!show_frame || DRW_state_is_select()) {
+ return;
+ }
+
+ float norm_obmat[4][4];
+ normalize_m4_m4(norm_obmat, ob->obmat);
+
+ for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ if (bgpic->flag & CAM_BGIMG_FLAG_DISABLED) {
+ continue;
+ }
+
+ float aspect = 1.0;
+ bool use_alpha_premult;
+ float mat[4][4];
+
+ /* retrieve the image we want to show, continue to next when no image could be found */
+ GPUTexture *tex = image_camera_background_texture_get(
+ bgpic, draw_ctx, pd, &aspect, &use_alpha_premult);
+
+ if (tex) {
+ image_camera_background_matrix_get(cam, bgpic, draw_ctx, aspect, mat);
+
+ mul_m4_m4m4(mat, norm_obmat, mat);
+ const bool is_foreground = (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != 0;
+
+ /* When drawing background we do 2 passes.
+ * - One alpha over, which works where background is visible.
+ * - One alpha under, works under partially visible objects. (only in cycles)
+ * This approach is not ideal and should be revisited.
+ **/
+ for (int i = 0; i < (is_foreground ? 1 : 2); i++) {
+ DRWPass *pass = is_foreground ? psl->image_foreground_ps :
+ ((i == 0) ? psl->image_background_under_ps :
+ psl->image_background_over_ps);
+ GPUShader *sh = OVERLAY_shader_image();
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ float color[4] = {1.0f, 1.0f, 1.0f, bgpic->alpha};
+ DRW_shgroup_uniform_texture(grp, "imgTexture", tex);
+ DRW_shgroup_uniform_bool_copy(grp, "imgPremultiplied", use_alpha_premult);
+ DRW_shgroup_uniform_bool_copy(grp, "imgAlphaBlend", true);
+ DRW_shgroup_uniform_bool_copy(grp, "imgLinear", !DRW_state_do_color_management());
+ DRW_shgroup_uniform_bool_copy(grp, "depthSet", true);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", color);
+ DRW_shgroup_call_obmat(grp, DRW_cache_quad_get(), mat);
+ }
+ }
+ }
+}
+
+void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const RegionView3D *rv3d = draw_ctx->rv3d;
+ GPUTexture *tex = NULL;
+ Image *ima = ob->data;
+ float mat[4][4];
+
+ const bool show_frame = BKE_object_empty_image_frame_is_visible_in_view3d(ob, rv3d);
+ const bool show_image = show_frame && BKE_object_empty_image_data_is_visible_in_view3d(ob, rv3d);
+ const bool use_alpha_blend = (ob->empty_image_flag & OB_EMPTY_IMAGE_USE_ALPHA_BLEND) != 0;
+ const bool use_alpha_premult = ima && (ima->alpha_mode == IMA_ALPHA_PREMUL);
+
+ if (!show_frame) {
+ return;
+ }
+
+ {
+ /* Calling 'BKE_image_get_size' may free the texture. Get the size from 'tex' instead,
+ * see: T59347 */
+ int size[2] = {0};
+ if (ima != NULL) {
+ tex = GPU_texture_from_blender(ima, ob->iuser, GL_TEXTURE_2D);
+ if (tex) {
+ size[0] = GPU_texture_orig_width(tex);
+ size[1] = GPU_texture_orig_height(tex);
+ }
+ }
+ CLAMP_MIN(size[0], 1);
+ CLAMP_MIN(size[1], 1);
+
+ float image_aspect[2];
+ overlay_image_calc_aspect(ob->data, size, image_aspect);
+
+ copy_m4_m4(mat, ob->obmat);
+ mul_v3_fl(mat[0], image_aspect[0] * 0.5f * ob->empty_drawsize);
+ mul_v3_fl(mat[1], image_aspect[1] * 0.5f * ob->empty_drawsize);
+ madd_v3_v3fl(mat[3], mat[0], ob->ima_ofs[0] * 2.0f + 1.0f);
+ madd_v3_v3fl(mat[3], mat[1], ob->ima_ofs[1] * 2.0f + 1.0f);
+ }
+
+ /* Use the actual depth if we are doing depth tests to determine the distance to the object */
+ char depth_mode = DRW_state_is_depth() ? OB_EMPTY_IMAGE_DEPTH_DEFAULT : ob->empty_image_depth;
+ DRWPass *pass = NULL;
+ switch (depth_mode) {
+ case OB_EMPTY_IMAGE_DEPTH_DEFAULT:
+ pass = (use_alpha_blend) ? psl->image_empties_blend_ps : psl->image_empties_ps;
+ break;
+ case OB_EMPTY_IMAGE_DEPTH_BACK:
+ pass = psl->image_empties_back_ps;
+ break;
+ case OB_EMPTY_IMAGE_DEPTH_FRONT:
+ pass = psl->image_empties_front_ps;
+ break;
+ }
+
+ if (show_frame) {
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+ OVERLAY_empty_shape(cb, mat, 1.0f, OB_EMPTY_IMAGE, color);
+ }
+
+ if (show_image && tex && ((ob->color[3] > 0.0f) || !use_alpha_blend)) {
+ GPUShader *sh = OVERLAY_shader_image();
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_texture(grp, "imgTexture", tex);
+ DRW_shgroup_uniform_bool_copy(grp, "imgPremultiplied", use_alpha_premult);
+ DRW_shgroup_uniform_bool_copy(grp, "imgAlphaBlend", use_alpha_blend);
+ DRW_shgroup_uniform_bool_copy(grp, "imgLinear", false);
+ DRW_shgroup_uniform_bool_copy(grp, "depthSet", depth_mode != OB_EMPTY_IMAGE_DEPTH_DEFAULT);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", ob->color);
+ DRW_shgroup_call_obmat(grp, DRW_cache_quad_get(), mat);
+ }
+}
+
+void OVERLAY_image_cache_finish(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_pass_sort_shgroup_reverse(psl->image_background_under_ps);
+ DRW_pass_sort_shgroup_z(psl->image_empties_blend_ps);
+ DRW_pass_sort_shgroup_z(psl->image_empties_front_ps);
+ DRW_pass_sort_shgroup_z(psl->image_empties_back_ps);
+}
+
+void OVERLAY_image_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ DRW_view_set_active(pd->view_reference_images);
+
+ DRW_draw_pass(psl->image_background_over_ps);
+ DRW_draw_pass(psl->image_background_under_ps);
+ DRW_draw_pass(psl->image_empties_back_ps);
+
+ DRW_draw_pass(psl->image_empties_ps);
+ DRW_draw_pass(psl->image_empties_blend_ps);
+
+ DRW_view_set_active(pd->view_default);
+}
+
+void OVERLAY_image_in_front_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ DRW_view_set_active(pd->view_reference_images);
+
+ DRW_draw_pass(psl->image_empties_front_ps);
+ DRW_draw_pass(psl->image_foreground_ps);
+
+ DRW_view_set_active(pd->view_default);
+
+ OVERLAY_image_free_movieclips_textures(vedata);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_lattice.c b/source/blender/draw/engines/overlay/overlay_lattice.c
new file mode 100644
index 00000000000..4e4081ee499
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_lattice.c
@@ -0,0 +1,78 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_edit_lattice_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->edit_lattice_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_edit_lattice_wire();
+ pd->edit_lattice_wires_grp = grp = DRW_shgroup_create(sh, psl->edit_lattice_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
+
+ sh = OVERLAY_shader_edit_lattice_point();
+ pd->edit_lattice_points_grp = grp = DRW_shgroup_create(sh, psl->edit_lattice_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ }
+}
+
+void OVERLAY_edit_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUBatch *geom;
+
+ geom = DRW_cache_lattice_wire_get(ob, true);
+ DRW_shgroup_call(pd->edit_lattice_wires_grp, geom, ob);
+
+ geom = DRW_cache_lattice_vert_overlay_get(ob);
+ DRW_shgroup_call(pd->edit_lattice_points_grp, geom, ob);
+}
+
+void OVERLAY_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+
+ struct GPUBatch *geom = DRW_cache_lattice_wire_get(ob, false);
+ OVERLAY_extra_wire(cb, geom, ob->obmat, color);
+}
+
+void OVERLAY_edit_lattice_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->edit_lattice_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_metaball.c b/source/blender/draw/engines/overlay/overlay_metaball.c
new file mode 100644
index 00000000000..a634aed812c
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_metaball.c
@@ -0,0 +1,143 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_meta_types.h"
+
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_mball.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_metaball_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
+
+#define BUF_INSTANCE DRW_shgroup_call_buffer_instance
+
+ for (int i = 0; i < 2; i++) {
+ DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->metaball_ps[i], state | pd->clipping_state | infront_state);
+
+ /* Reuse armature shader as it's perfect to outline ellipsoids. */
+ struct GPUVertFormat *format = formats->instance_bone;
+ struct GPUShader *sh = OVERLAY_shader_armature_sphere(true);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->metaball_ps[i]);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ pd->mball.handle[i] = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get());
+ }
+}
+
+static void metaball_instance_data_set(
+ BoneInstanceData *data, Object *ob, const float *pos, const float radius, const float color[4])
+{
+ /* Bone point radius is 0.05. Compensate for that. */
+ mul_v3_v3fl(data->mat[0], ob->obmat[0], radius / 0.05f);
+ mul_v3_v3fl(data->mat[1], ob->obmat[1], radius / 0.05f);
+ mul_v3_v3fl(data->mat[2], ob->obmat[2], radius / 0.05f);
+ mul_v3_m4v3(data->mat[3], ob->obmat, pos);
+ /* WATCH: Reminder, alpha is wiresize. */
+ OVERLAY_bone_instance_data_set_color(data, color);
+}
+
+void OVERLAY_edit_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ const bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+ const bool is_select = DRW_state_is_select();
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ MetaBall *mb = ob->data;
+
+ const float *color;
+ const float col_radius[4] = {0.63f, 0.19f, 0.19f, 1.0f}; /* 0x3030A0 */
+ const float col_radius_select[4] = {0.94f, 0.63f, 0.63f, 1.0f}; /* 0xA0A0F0 */
+ const float col_stiffness[4] = {0.19f, 0.63f, 0.19f, 1.0f}; /* 0x30A030 */
+ const float col_stiffness_select[4] = {0.63f, 0.94f, 0.63f, 1.0f}; /* 0xA0F0A0 */
+
+ int select_id = 0;
+ if (is_select) {
+ const Object *orig_object = DEG_get_original_object(ob);
+ select_id = orig_object->runtime.select_id;
+ }
+
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
+ const bool is_selected = (ml->flag & SELECT) != 0;
+ const bool is_scale_radius = (ml->flag & MB_SCALE_RAD) != 0;
+ float stiffness_radius = ml->rad * atanf(ml->s) / (float)M_PI_2;
+ BoneInstanceData instdata;
+
+ if (is_select) {
+ DRW_select_load_id(select_id | MBALLSEL_RADIUS);
+ }
+ color = (is_selected && is_scale_radius) ? col_radius_select : col_radius;
+ metaball_instance_data_set(&instdata, ob, &ml->x, ml->rad, color);
+ DRW_buffer_add_entry_struct(pd->mball.handle[do_in_front], &instdata);
+
+ if (is_select) {
+ DRW_select_load_id(select_id | MBALLSEL_STIFF);
+ }
+ color = (is_selected && !is_scale_radius) ? col_stiffness_select : col_stiffness;
+ metaball_instance_data_set(&instdata, ob, &ml->x, stiffness_radius, color);
+ DRW_buffer_add_entry_struct(pd->mball.handle[do_in_front], &instdata);
+
+ select_id += 0x10000;
+ }
+}
+
+void OVERLAY_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ const bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ MetaBall *mb = ob->data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+
+ LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
+ /* Draw radius only. */
+ BoneInstanceData instdata;
+ metaball_instance_data_set(&instdata, ob, &ml->x, ml->rad, color);
+ DRW_buffer_add_entry_struct(pd->mball.handle[do_in_front], &instdata);
+ }
+}
+
+void OVERLAY_metaball_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->metaball_ps[0]);
+}
+
+void OVERLAY_metaball_in_front_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->metaball_ps[1]);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_motion_path.c b/source/blender/draw/engines/overlay/overlay_motion_path.c
new file mode 100644
index 00000000000..349f17d3d7d
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_motion_path.c
@@ -0,0 +1,231 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_string.h"
+
+#include "DNA_armature_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "GPU_batch.h"
+
+#include "UI_resources.h"
+
+#include "draw_manager_text.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_motion_path_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DRWShadingGroup *grp;
+ GPUShader *sh;
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ DRW_PASS_CREATE(psl->motion_paths_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_motion_path_line();
+ pd->motion_path_lines_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+ sh = OVERLAY_shader_motion_path_vert();
+ pd->motion_path_points_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+}
+
+/* Just convert the CPU cache to GPU cache. */
+/* T0D0(fclem) This should go into a draw_cache_impl_motionpath. */
+static GPUVertBuf *mpath_vbo_get(bMotionPath *mpath)
+{
+ if (!mpath->points_vbo) {
+ GPUVertFormat format = {0};
+ /* Match structure of bMotionPathVert. */
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "flag", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ mpath->points_vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(mpath->points_vbo, mpath->length);
+ /* meh... a useless memcpy. */
+ memcpy(mpath->points_vbo->data, mpath->points, sizeof(bMotionPathVert) * mpath->length);
+ }
+ return mpath->points_vbo;
+}
+
+static GPUBatch *mpath_batch_line_get(bMotionPath *mpath)
+{
+ if (!mpath->batch_line) {
+ mpath->batch_line = GPU_batch_create(GPU_PRIM_LINE_STRIP, mpath_vbo_get(mpath), NULL);
+ }
+ return mpath->batch_line;
+}
+
+static GPUBatch *mpath_batch_points_get(bMotionPath *mpath)
+{
+ if (!mpath->batch_points) {
+ mpath->batch_points = GPU_batch_create(GPU_PRIM_POINTS, mpath_vbo_get(mpath), NULL);
+ }
+ return mpath->batch_points;
+}
+
+static void motion_path_get_frame_range_to_draw(bAnimVizSettings *avs,
+ bMotionPath *mpath,
+ int current_frame,
+ int *r_start,
+ int *r_end,
+ int *r_step)
+{
+ int start, end;
+
+ if (avs->path_type == MOTIONPATH_TYPE_ACFRA) {
+ start = current_frame - avs->path_bc;
+ end = current_frame + avs->path_ac + 1;
+ }
+ else {
+ start = avs->path_sf;
+ end = avs->path_ef;
+ }
+
+ if (start > end) {
+ SWAP(int, start, end);
+ }
+
+ CLAMP(start, mpath->start_frame, mpath->end_frame);
+ CLAMP(end, mpath->start_frame, mpath->end_frame);
+
+ *r_start = start;
+ *r_end = end;
+ *r_step = max_ii(avs->path_step, 1);
+}
+
+static void motion_path_cache(OVERLAY_Data *vedata,
+ Object *ob,
+ bPoseChannel *pchan,
+ bAnimVizSettings *avs,
+ bMotionPath *mpath)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ int txt_flag = DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_ASCII;
+ int cfra = (int)DEG_get_ctime(draw_ctx->depsgraph);
+ bool selected = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->base_flag & BASE_SELECTED);
+ bool show_keyframes = (avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) != 0;
+ bool show_keyframes_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0;
+ bool show_frame_no = (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) != 0;
+ bool show_lines = (mpath->flag & MOTIONPATH_FLAG_LINES) != 0;
+ float no_custom_col[3] = {-1.0f, -1.0f, -1.0f};
+ float *color = (mpath->flag & MOTIONPATH_FLAG_CUSTOM) ? mpath->color : no_custom_col;
+
+ int sfra, efra, stepsize;
+ motion_path_get_frame_range_to_draw(avs, mpath, cfra, &sfra, &efra, &stepsize);
+
+ int len = efra - sfra;
+ if (len == 0) {
+ return;
+ }
+ int start_index = sfra - mpath->start_frame;
+
+ /* Draw curve-line of path. */
+ if (show_lines) {
+ int motion_path_settings[4] = {cfra, sfra, efra, mpath->start_frame};
+ DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->motion_path_lines_grp);
+ DRW_shgroup_uniform_ivec4_copy(grp, "mpathLineSettings", motion_path_settings);
+ DRW_shgroup_uniform_int_copy(grp, "lineThickness", mpath->line_thickness);
+ DRW_shgroup_uniform_bool_copy(grp, "selected", selected);
+ DRW_shgroup_uniform_vec3_copy(grp, "customColor", color);
+ /* Only draw the required range. */
+ DRW_shgroup_call_range(grp, mpath_batch_line_get(mpath), start_index, len);
+ }
+
+ /* Draw points. */
+ {
+ int pt_size = max_ii(mpath->line_thickness - 1, 1);
+ int motion_path_settings[4] = {pt_size, cfra, mpath->start_frame, stepsize};
+ DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->motion_path_points_grp);
+ DRW_shgroup_uniform_ivec4_copy(grp, "mpathPointSettings", motion_path_settings);
+ DRW_shgroup_uniform_bool_copy(grp, "showKeyFrames", show_keyframes);
+ DRW_shgroup_uniform_vec3_copy(grp, "customColor", color);
+ /* Only draw the required range. */
+ DRW_shgroup_call_range(grp, mpath_batch_points_get(mpath), start_index, len);
+ }
+
+ /* Draw frame numbers at each framestep value */
+ if (show_frame_no || (show_keyframes_no && show_keyframes)) {
+ int i;
+ uchar col[4], col_kf[4];
+ UI_GetThemeColor3ubv(TH_TEXT_HI, col);
+ UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col_kf);
+ col[3] = col_kf[3] = 255;
+
+ bMotionPathVert *mpv = mpath->points + start_index;
+ for (i = 0; i < len; i += stepsize, mpv += stepsize) {
+ int frame = sfra + i;
+ char numstr[32];
+ size_t numstr_len;
+ bool is_keyframe = (mpv->flag & MOTIONPATH_VERT_KEY) != 0;
+
+ if ((show_keyframes && show_keyframes_no && is_keyframe) || (show_frame_no && (i == 0))) {
+ numstr_len = BLI_snprintf(numstr, sizeof(numstr), " %d", frame);
+ DRW_text_cache_add(
+ dt, mpv->co, numstr, numstr_len, 0, 0, txt_flag, (is_keyframe) ? col_kf : col);
+ }
+ else if (show_frame_no) {
+ bMotionPathVert *mpvP = (mpv - stepsize);
+ bMotionPathVert *mpvN = (mpv + stepsize);
+ /* Only draw framenum if several consecutive highlighted points don't occur on same point.
+ */
+ if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) {
+ numstr_len = BLI_snprintf(numstr, sizeof(numstr), " %d", frame);
+ DRW_text_cache_add(dt, mpv->co, numstr, numstr_len, 0, 0, txt_flag, col);
+ }
+ }
+ }
+ }
+}
+
+void OVERLAY_motion_path_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ if (ob->type == OB_ARMATURE) {
+ if (OVERLAY_armature_is_pose_mode(ob, draw_ctx)) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->mpath) {
+ motion_path_cache(vedata, ob, pchan, &ob->pose->avs, pchan->mpath);
+ }
+ }
+ }
+ }
+
+ if (ob->mpath) {
+ motion_path_cache(vedata, ob, NULL, &ob->avs, ob->mpath);
+ }
+}
+
+void OVERLAY_motion_path_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->motion_paths_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c
new file mode 100644
index 00000000000..a0c7f575677
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_outline.c
@@ -0,0 +1,353 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_lightprobe_types.h"
+
+#include "UI_resources.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_outline_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_TextureList *txl = vedata->txl;
+
+ if (DRW_state_is_fbo()) {
+ /* TODO only alloc if needed. */
+ /* XXX TODO GPU_R16UI can overflow, it would cause no harm
+ * (only bad colored or missing outlines) but we should
+ * use 32bits only if the scene have that many objects */
+ DRW_texture_ensure_fullscreen_2d(&txl->temp_depth_tx, GPU_DEPTH24_STENCIL8, 0);
+ DRW_texture_ensure_fullscreen_2d(&txl->outlines_id_tx, GPU_R16UI, 0);
+ GPU_framebuffer_ensure_config(
+ &fbl->outlines_prepass_fb,
+ {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(txl->outlines_id_tx)});
+
+ for (int i = 0; i < 2; i++) {
+ DRW_texture_ensure_fullscreen_2d(&txl->outlines_color_tx[i], GPU_RGBA8, DRW_TEX_FILTER);
+ GPU_framebuffer_ensure_config(
+ &fbl->outlines_process_fb[i],
+ {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->outlines_color_tx[i])});
+ }
+ }
+}
+
+static int shgroup_theme_id_to_outline_id(int theme_id, const int base_flag)
+{
+ if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
+ switch (theme_id) {
+ case TH_ACTIVE:
+ case TH_SELECT:
+ return 2;
+ case TH_TRANSFORM:
+ return 0;
+ default:
+ return -1;
+ }
+ }
+
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return 3;
+ case TH_SELECT:
+ return 1;
+ case TH_TRANSFORM:
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OVERLAY_PrivateData *pd,
+ int theme_id,
+ const int base_flag)
+{
+ int outline_id = shgroup_theme_id_to_outline_id(theme_id, base_flag);
+ switch (outline_id) {
+ case 3: /* TH_ACTIVE */
+ return pd->outlines_active_grp;
+ case 2: /* Duplis */
+ return pd->outlines_select_dupli_grp;
+ case 1: /* TH_SELECT */
+ return pd->outlines_select_grp;
+ case 0: /* TH_TRANSFORM */
+ return pd->outlines_transform_grp;
+ default:
+ return NULL;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_probe_outline_or_null(OVERLAY_PrivateData *pd,
+ int theme_id,
+ const int base_flag)
+{
+ int outline_id = shgroup_theme_id_to_outline_id(theme_id, base_flag);
+ switch (outline_id) {
+ case 3: /* TH_ACTIVE */
+ return pd->outlines_probe_active_grp;
+ case 2: /* Duplis */
+ return pd->outlines_probe_select_dupli_grp;
+ case 1: /* TH_SELECT */
+ return pd->outlines_probe_select_grp;
+ case 0: /* TH_TRANSFORM */
+ return pd->outlines_probe_transform_grp;
+ default:
+ return NULL;
+ }
+}
+
+static DRWShadingGroup *outline_shgroup(DRWPass *pass, int outline_id, GPUShader *sh)
+{
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
+ return grp;
+}
+
+void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DRWShadingGroup *grp = NULL;
+
+ const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH);
+ const bool do_outline_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
+ const bool do_large_expand = ((U.pixelsize > 1.0) && (outline_width > 2.0f)) ||
+ (outline_width > 4.0f);
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->outlines_prepass_ps, state | pd->clipping_state);
+
+ GPUShader *sh_grid = OVERLAY_shader_outline_prepass_grid();
+ GPUShader *sh_geom = OVERLAY_shader_outline_prepass(pd->xray_enabled_and_not_wire);
+ GPUShader *sh = OVERLAY_shader_outline_prepass(false);
+
+ pd->outlines_transform_grp = outline_shgroup(psl->outlines_prepass_ps, 0, sh_geom);
+ pd->outlines_select_grp = outline_shgroup(psl->outlines_prepass_ps, 1, sh_geom);
+ pd->outlines_select_dupli_grp = outline_shgroup(psl->outlines_prepass_ps, 2, sh_geom);
+ pd->outlines_active_grp = outline_shgroup(psl->outlines_prepass_ps, 3, sh_geom);
+
+ pd->outlines_probe_transform_grp = outline_shgroup(psl->outlines_prepass_ps, 0, sh);
+ pd->outlines_probe_select_grp = outline_shgroup(psl->outlines_prepass_ps, 1, sh);
+ pd->outlines_probe_select_dupli_grp = outline_shgroup(psl->outlines_prepass_ps, 2, sh);
+ pd->outlines_probe_active_grp = outline_shgroup(psl->outlines_prepass_ps, 3, sh);
+
+ pd->outlines_probe_grid_grp = grp = DRW_shgroup_create(sh_grid, psl->outlines_prepass_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ }
+
+ /* outlines_prepass_ps is still needed for selection of probes. */
+ if (!(pd->v3d_flag & V3D_SELECT_OUTLINE)) {
+ return;
+ }
+
+ {
+ DRW_PASS_CREATE(psl->outlines_detect_ps, DRW_STATE_WRITE_COLOR);
+ DRW_PASS_CREATE(psl->outlines_expand_ps, DRW_STATE_WRITE_COLOR);
+ DRW_PASS_CREATE(psl->outlines_bleed_ps, DRW_STATE_WRITE_COLOR);
+ DRW_PASS_CREATE(psl->outlines_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
+
+ GPUShader *sh = OVERLAY_shader_outline_detect(pd->xray_enabled_and_not_wire);
+
+ grp = DRW_shgroup_create(sh, psl->outlines_detect_ps);
+ /* Don't occlude the "outline" detection pass if in xray mode (too much flickering). */
+ DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", (pd->xray_enabled) ? 1.0f : 0.35f);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineId", &txl->outlines_id_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &txl->temp_depth_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ if (do_outline_expand) {
+ sh = OVERLAY_shader_outline_expand(do_large_expand);
+ grp = DRW_shgroup_create(sh, psl->outlines_expand_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[0]);
+ DRW_shgroup_uniform_bool_copy(grp, "doExpand", true);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ sh = OVERLAY_shader_outline_expand(false);
+ grp = DRW_shgroup_create(sh, psl->outlines_bleed_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[1]);
+ DRW_shgroup_uniform_bool_copy(grp, "doExpand", false);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ else {
+ sh = OVERLAY_shader_outline_expand(false);
+ grp = DRW_shgroup_create(sh, psl->outlines_expand_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[0]);
+ DRW_shgroup_uniform_bool_copy(grp, "doExpand", false);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+
+ GPUTexture **outline_tx = &txl->outlines_color_tx[do_outline_expand ? 0 : 1];
+ sh = OVERLAY_shader_outline_resolve();
+
+ grp = DRW_shgroup_create(sh, psl->outlines_resolve_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineBluredColor", outline_tx);
+ DRW_shgroup_uniform_vec2_copy(grp, "rcpDimensions", DRW_viewport_invert_size_get());
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+}
+
+static void outline_lightprobe(OVERLAY_PrivateData *pd, Object *ob, ViewLayer *view_layer)
+{
+ DRWShadingGroup *grp;
+ LightProbe *prb = (LightProbe *)ob->data;
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+
+ if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ float corner[3];
+ float increment[3][3];
+ /* Update transforms */
+ float cell_dim[3], half_cell_dim[3];
+ cell_dim[0] = 2.0f / (float)(prb->grid_resolution_x);
+ cell_dim[1] = 2.0f / (float)(prb->grid_resolution_y);
+ cell_dim[2] = 2.0f / (float)(prb->grid_resolution_z);
+
+ mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f);
+
+ /* First cell. */
+ copy_v3_fl(corner, -1.0f);
+ add_v3_v3(corner, half_cell_dim);
+ mul_m4_v3(ob->obmat, corner);
+
+ /* Opposite neighbor cell. */
+ copy_v3_fl3(increment[0], cell_dim[0], 0.0f, 0.0f);
+ copy_v3_fl3(increment[1], 0.0f, cell_dim[1], 0.0f);
+ copy_v3_fl3(increment[2], 0.0f, 0.0f, cell_dim[2]);
+
+ for (int i = 0; i < 3; i++) {
+ add_v3_v3(increment[i], half_cell_dim);
+ add_v3_fl(increment[i], -1.0f);
+ mul_m4_v3(ob->obmat, increment[i]);
+ sub_v3_v3(increment[i], corner);
+ }
+
+ int outline_id = shgroup_theme_id_to_outline_id(theme_id, ob->base_flag);
+ uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
+ grp = DRW_shgroup_create_sub(pd->outlines_probe_grid_grp);
+ DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
+ DRW_shgroup_uniform_vec3_copy(grp, "corner", corner);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_x", increment[0]);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_y", increment[1]);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_z", increment[2]);
+ DRW_shgroup_uniform_ivec3_copy(grp, "grid_resolution", &prb->grid_resolution_x);
+ DRW_shgroup_call_procedural_points(grp, NULL, cell_count);
+ }
+ else if (prb->type == LIGHTPROBE_TYPE_PLANAR && (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
+ grp = shgroup_theme_id_to_probe_outline_or_null(pd, theme_id, ob->base_flag);
+ DRW_shgroup_call_no_cull(grp, DRW_cache_quad_get(), ob);
+ }
+}
+
+void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
+ Object *ob,
+ OVERLAY_DupliData *dupli,
+ bool init_dupli)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ struct GPUBatch *geom;
+ DRWShadingGroup *shgroup = NULL;
+
+ if (ob->type == OB_LIGHTPROBE) {
+ outline_lightprobe(pd, ob, draw_ctx->view_layer);
+ return;
+ }
+
+ if (dupli && !init_dupli) {
+ geom = dupli->outline_geom;
+ shgroup = dupli->outline_shgrp;
+ }
+ else {
+ /* This fixes only the biggest case which is a plane in ortho view. */
+ int flat_axis = 0;
+ bool is_flat_object_viewed_from_side = ((draw_ctx->rv3d->persp == RV3D_ORTHO) &&
+ DRW_object_is_flat(ob, &flat_axis) &&
+ DRW_object_axis_orthogonal_to_view(ob, flat_axis));
+
+ if (pd->xray_enabled_and_not_wire || is_flat_object_viewed_from_side) {
+ geom = DRW_cache_object_edge_detection_get(ob, NULL);
+ }
+ else {
+ geom = DRW_cache_object_surface_get(ob);
+ }
+
+ if (geom) {
+ int theme_id = DRW_object_wire_theme_get(ob, draw_ctx->view_layer, NULL);
+ shgroup = shgroup_theme_id_to_outline_or_null(pd, theme_id, ob->base_flag);
+ }
+ }
+
+ if (shgroup && geom) {
+ DRW_shgroup_call(shgroup, geom, ob);
+ }
+
+ if (init_dupli) {
+ dupli->outline_shgrp = shgroup;
+ dupli->outline_geom = geom;
+ }
+}
+
+void OVERLAY_outline_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_PassList *psl = vedata->psl;
+ float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ bool do_outlines = psl->outlines_prepass_ps != NULL &&
+ !DRW_pass_is_empty(psl->outlines_prepass_ps);
+
+ if (DRW_state_is_fbo() && do_outlines) {
+ DRW_stats_group_start("Outlines");
+
+ /* Render filled polygon on a separate framebuffer */
+ GPU_framebuffer_bind(fbl->outlines_prepass_fb);
+ GPU_framebuffer_clear_color_depth(fbl->outlines_prepass_fb, clearcol, 1.0f);
+ DRW_draw_pass(psl->outlines_prepass_ps);
+
+ /* Search outline pixels */
+ GPU_framebuffer_bind(fbl->outlines_process_fb[0]);
+ DRW_draw_pass(psl->outlines_detect_ps);
+
+ /* Expand outline to form a 3px wide line */
+ GPU_framebuffer_bind(fbl->outlines_process_fb[1]);
+ DRW_draw_pass(psl->outlines_expand_ps);
+
+ /* Bleed color so the AA can do it's stuff */
+ GPU_framebuffer_bind(fbl->outlines_process_fb[0]);
+ DRW_draw_pass(psl->outlines_bleed_ps);
+
+ /* restore main framebuffer */
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ DRW_draw_pass(psl->outlines_resolve_ps);
+
+ DRW_stats_group_end();
+ }
+ else if (DRW_state_is_select()) {
+ /* Render probes spheres/planes so we can select them. */
+ DRW_draw_pass(psl->outlines_prepass_ps);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_paint.c b/source/blender/draw/engines/overlay/overlay_paint.c
new file mode 100644
index 00000000000..4e73770472d
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_paint.c
@@ -0,0 +1,211 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_mesh_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_paint_cache_init(OVERLAY_Data *vedata)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+ DRWState state;
+
+ const bool use_alpha_blending = (draw_ctx->v3d->shading.type == OB_WIRE);
+ const bool draw_contours = (pd->overlay.wpaint_flag & V3D_OVERLAY_WPAINT_CONTOURS) != 0;
+ float opacity = 0.0f;
+
+ switch (pd->ctx_mode) {
+ case CTX_MODE_POSE:
+ case CTX_MODE_PAINT_WEIGHT: {
+ opacity = pd->overlay.weight_paint_mode_opacity;
+ if (opacity > 0.0f) {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
+ state |= use_alpha_blending ? DRW_STATE_BLEND_ALPHA : DRW_STATE_BLEND_MUL;
+ DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_paint_weight();
+ pd->paint_surf_grp = grp = DRW_shgroup_create(sh, psl->paint_color_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "drawContours", draw_contours);
+ DRW_shgroup_uniform_bool_copy(grp, "useAlphaBlend", use_alpha_blending);
+ DRW_shgroup_uniform_float_copy(grp, "opacity", opacity);
+ DRW_shgroup_uniform_texture(grp, "colorramp", G_draw.weight_ramp);
+ }
+ break;
+ }
+ case CTX_MODE_PAINT_VERTEX: {
+ opacity = pd->overlay.vertex_paint_mode_opacity;
+ if (opacity > 0.0f) {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
+ state |= use_alpha_blending ? DRW_STATE_BLEND_ALPHA : DRW_STATE_BLEND_MUL;
+ DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_paint_vertcol();
+ pd->paint_surf_grp = grp = DRW_shgroup_create(sh, psl->paint_color_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "useAlphaBlend", use_alpha_blending);
+ DRW_shgroup_uniform_float_copy(grp, "opacity", opacity);
+ }
+ break;
+ }
+ case CTX_MODE_PAINT_TEXTURE: {
+ const ImagePaintSettings *imapaint = &draw_ctx->scene->toolsettings->imapaint;
+ const bool mask_enabled = imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL &&
+ imapaint->stencil != NULL;
+
+ opacity = mask_enabled ? pd->overlay.texture_paint_mode_opacity : 0.0f;
+ if (opacity > 0.0f) {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state);
+
+ GPUTexture *tex = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D);
+
+ const bool mask_premult = (imapaint->stencil->alpha_mode == IMA_ALPHA_PREMUL);
+ const bool mask_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0;
+ sh = OVERLAY_shader_paint_texture();
+ pd->paint_surf_grp = grp = DRW_shgroup_create(sh, psl->paint_color_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "opacity", opacity);
+ DRW_shgroup_uniform_bool_copy(grp, "maskPremult", mask_premult);
+ DRW_shgroup_uniform_vec3_copy(grp, "maskColor", imapaint->stencil_col);
+ DRW_shgroup_uniform_bool_copy(grp, "maskInvertStencil", mask_inverted);
+ DRW_shgroup_uniform_texture(grp, "maskImage", tex);
+ }
+ break;
+ }
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ if (opacity <= 0.0f) {
+ psl->paint_color_ps = NULL;
+ pd->paint_surf_grp = NULL;
+ }
+
+ {
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->paint_overlay_ps, state | pd->clipping_state);
+ sh = OVERLAY_shader_paint_face();
+ pd->paint_face_grp = grp = DRW_shgroup_create(sh, psl->paint_overlay_ps);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", (float[4]){1.0f, 1.0f, 1.0f, 0.2f});
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+ sh = OVERLAY_shader_paint_wire();
+ pd->paint_wire_selected_grp = grp = DRW_shgroup_create(sh, psl->paint_overlay_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "useSelect", true);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+ pd->paint_wire_grp = grp = DRW_shgroup_create(sh, psl->paint_overlay_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "useSelect", false);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+ sh = OVERLAY_shader_paint_point();
+ pd->paint_point_grp = grp = DRW_shgroup_create(sh, psl->paint_overlay_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ }
+}
+
+void OVERLAY_paint_texture_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUBatch *geom = NULL;
+
+ const Mesh *me_orig = DEG_get_original_object(ob)->data;
+ const bool use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+
+ if (pd->paint_surf_grp) {
+ geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
+ DRW_shgroup_call(pd->paint_surf_grp, geom, ob);
+ }
+
+ if (use_face_sel) {
+ geom = DRW_cache_mesh_surface_get(ob);
+ DRW_shgroup_call(pd->paint_face_grp, geom, ob);
+ }
+}
+
+void OVERLAY_paint_vertex_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUBatch *geom = NULL;
+
+ const Mesh *me = ob->data;
+ const Mesh *me_orig = DEG_get_original_object(ob)->data;
+ const bool use_wire = (pd->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE) != 0;
+ const bool use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+
+ if (pd->paint_surf_grp) {
+ if (ob->mode == OB_MODE_VERTEX_PAINT) {
+ if (me->mloopcol == NULL) {
+ return;
+ }
+ geom = DRW_cache_mesh_surface_vertpaint_get(ob);
+ }
+ else {
+ geom = DRW_cache_mesh_surface_weights_get(ob);
+ }
+ DRW_shgroup_call(pd->paint_surf_grp, geom, ob);
+ }
+
+ if (use_face_sel || use_wire) {
+ geom = DRW_cache_mesh_surface_edges_get(ob);
+ DRW_shgroup_call(use_face_sel ? pd->paint_wire_selected_grp : pd->paint_wire_grp, geom, ob);
+ }
+
+ if (use_face_sel) {
+ geom = DRW_cache_mesh_surface_get(ob);
+ DRW_shgroup_call(pd->paint_face_grp, geom, ob);
+ }
+
+ if (use_vert_sel) {
+ geom = DRW_cache_mesh_all_verts_get(ob);
+ DRW_shgroup_call(pd->paint_point_grp, geom, ob);
+ }
+}
+
+void OVERLAY_paint_weight_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_paint_vertex_cache_populate(vedata, ob);
+}
+
+void OVERLAY_paint_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ if (psl->paint_color_ps) {
+ DRW_view_set_active(NULL);
+ DRW_draw_pass(psl->paint_color_ps);
+ }
+ DRW_draw_pass(psl->paint_overlay_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_particle.c b/source/blender/draw/engines/overlay/overlay_particle.c
new file mode 100644
index 00000000000..f7b6fa7919b
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_particle.c
@@ -0,0 +1,217 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_particle_types.h"
+
+#include "BKE_pointcache.h"
+
+#include "ED_particle.h"
+
+#include "overlay_private.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Edit Particles
+ * \{ */
+
+void OVERLAY_edit_particle_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
+ GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ pd->edit_particle.use_weight = (pset->brushtype == PE_BRUSH_WEIGHT);
+ pd->edit_particle.select_mode = pset->selectmode;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->edit_particle_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_edit_particle_strand();
+ pd->edit_particle_strand_grp = grp = DRW_shgroup_create(sh, psl->edit_particle_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "useWeight", pd->edit_particle.use_weight);
+ DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
+
+ sh = OVERLAY_shader_edit_particle_point();
+ pd->edit_particle_point_grp = grp = DRW_shgroup_create(sh, psl->edit_particle_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+}
+
+void OVERLAY_edit_particle_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
+
+ /* Usually the edit structure is created by Particle Edit Mode Toggle
+ * operator, but sometimes it's invoked after tagging hair as outdated
+ * (for example, when toggling edit mode). That makes it impossible to
+ * create edit structure for until after next dependency graph evaluation.
+ *
+ * Ideally, the edit structure will be created here already via some
+ * dependency graph callback or so, but currently trying to make it nicer
+ * only causes bad level calls and breaks design from the past.
+ */
+ Object *ob_orig = DEG_get_original_object(ob);
+ PTCacheEdit *edit = PE_create_current(draw_ctx->depsgraph, scene_orig, ob_orig);
+ if (edit == NULL) {
+ /* Happens when trying to edit particles in EMITTER mode without
+ * having them cached.
+ */
+ return;
+ }
+ /* NOTE: We need to pass evaluated particle system, which we need
+ * to find first.
+ */
+ ParticleSystem *psys = ob->particlesystem.first;
+ LISTBASE_FOREACH (ParticleSystem *, psys_orig, &ob_orig->particlesystem) {
+ if (PE_get_current_from_psys(psys_orig) == edit) {
+ break;
+ }
+ psys = psys->next;
+ }
+ if (psys == NULL) {
+ printf("Error getting evaluated particle system for edit.\n");
+ return;
+ }
+
+ struct GPUBatch *geom;
+ {
+ geom = DRW_cache_particles_get_edit_strands(ob, psys, edit, pd->edit_particle.use_weight);
+ DRW_shgroup_call(pd->edit_particle_strand_grp, geom, NULL);
+ }
+
+ if (pd->edit_particle.select_mode == SCE_SELECT_POINT) {
+ geom = DRW_cache_particles_get_edit_inner_points(ob, psys, edit);
+ DRW_shgroup_call(pd->edit_particle_point_grp, geom, NULL);
+ }
+
+ if (ELEM(pd->edit_particle.select_mode, SCE_SELECT_POINT, SCE_SELECT_END)) {
+ geom = DRW_cache_particles_get_edit_tip_points(ob, psys, edit);
+ DRW_shgroup_call(pd->edit_particle_point_grp, geom, NULL);
+ }
+}
+
+void OVERLAY_edit_particle_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->edit_particle_ps);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Particles
+ * \{ */
+
+void OVERLAY_particle_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
+ GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ pd->edit_particle.use_weight = (pset->brushtype == PE_BRUSH_WEIGHT);
+ pd->edit_particle.select_mode = pset->selectmode;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->particle_ps, state | pd->clipping_state);
+
+ sh = OVERLAY_shader_particle_dot();
+ pd->particle_dots_grp = grp = DRW_shgroup_create(sh, psl->particle_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture_persistent(grp, "weightTex", G_draw.ramp);
+
+ sh = OVERLAY_shader_particle_shape();
+ pd->particle_shapes_grp = grp = DRW_shgroup_create(sh, psl->particle_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture_persistent(grp, "weightTex", G_draw.ramp);
+}
+
+void OVERLAY_particle_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
+ if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+ continue;
+ }
+
+ ParticleSettings *part = psys->part;
+ int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+ if (part->type == PART_HAIR) {
+ /* Hairs should have been rendered by the render engine.*/
+ continue;
+ }
+
+ if (!ELEM(draw_as, PART_DRAW_NOT, PART_DRAW_OB, PART_DRAW_GR)) {
+ struct GPUBatch *geom = DRW_cache_particles_get_dots(ob, psys);
+ struct GPUBatch *shape = NULL;
+ DRWShadingGroup *grp;
+
+ /* TODO(fclem) Here would be a good place for preemptive culling. */
+
+ /* fclem: Is color even usefull in our modern context? */
+ Material *ma = give_current_material(ob, part->omat);
+ float color[4] = {0.6f, 0.6f, 0.6f, part->draw_size};
+ if (ma != NULL) {
+ copy_v3_v3(color, &ma->r);
+ }
+
+ switch (draw_as) {
+ default:
+ case PART_DRAW_DOT:
+ grp = DRW_shgroup_create_sub(pd->particle_dots_grp);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", color);
+ DRW_shgroup_call(grp, geom, NULL);
+ break;
+ case PART_DRAW_AXIS:
+ case PART_DRAW_CIRC:
+ case PART_DRAW_CROSS:
+ grp = DRW_shgroup_create_sub(pd->particle_shapes_grp);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", color);
+ shape = DRW_cache_particles_get_prim(draw_as);
+ DRW_shgroup_call_instances_with_attribs(grp, NULL, shape, geom);
+ break;
+ }
+ }
+ }
+}
+
+void OVERLAY_particle_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->particle_ps);
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
new file mode 100644
index 00000000000..6b030b65ac0
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_private.h
@@ -0,0 +1,585 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __OVERLAY_PRIVATE_H__
+#define __OVERLAY_PRIVATE_H__
+
+#ifdef __APPLE__
+# define USE_GEOM_SHADER_WORKAROUND 1
+#else
+# define USE_GEOM_SHADER_WORKAROUND 0
+#endif
+
+typedef struct OVERLAY_FramebufferList {
+ struct GPUFrameBuffer *overlay_default_fb;
+ struct GPUFrameBuffer *overlay_line_fb;
+ struct GPUFrameBuffer *overlay_color_only_fb;
+ struct GPUFrameBuffer *overlay_in_front_fb;
+ struct GPUFrameBuffer *outlines_prepass_fb;
+ struct GPUFrameBuffer *outlines_process_fb[2];
+} OVERLAY_FramebufferList;
+
+typedef struct OVERLAY_TextureList {
+ struct GPUTexture *temp_depth_tx;
+ struct GPUTexture *dummy_depth_tx;
+ struct GPUTexture *outlines_id_tx;
+ struct GPUTexture *outlines_color_tx[2];
+ struct GPUTexture *overlay_color_tx;
+ struct GPUTexture *overlay_color_history_tx;
+ struct GPUTexture *overlay_line_tx;
+ struct GPUTexture *edit_mesh_occlude_wire_tx;
+} OVERLAY_TextureList;
+
+#define NOT_IN_FRONT 0
+#define IN_FRONT 1
+
+typedef struct OVERLAY_PassList {
+ DRWPass *antialiasing_ps;
+ DRWPass *armature_ps[2];
+ DRWPass *armature_bone_select_ps;
+ DRWPass *armature_transp_ps;
+ DRWPass *edit_curve_wire_ps[2];
+ DRWPass *edit_curve_handle_ps;
+ DRWPass *edit_lattice_ps;
+ DRWPass *edit_mesh_depth_ps[2];
+ DRWPass *edit_mesh_verts_ps[2];
+ DRWPass *edit_mesh_edges_ps[2];
+ DRWPass *edit_mesh_faces_ps[2];
+ DRWPass *edit_mesh_faces_cage_ps[2];
+ DRWPass *edit_mesh_analysis_ps;
+ DRWPass *edit_mesh_normals_ps;
+ DRWPass *edit_mesh_weight_ps;
+ DRWPass *edit_particle_ps;
+ DRWPass *edit_text_overlay_ps;
+ DRWPass *edit_text_wire_ps[2];
+ DRWPass *extra_ps[2];
+ DRWPass *extra_blend_ps;
+ DRWPass *extra_centers_ps;
+ DRWPass *facing_ps;
+ DRWPass *grid_ps;
+ DRWPass *image_background_under_ps;
+ DRWPass *image_background_over_ps;
+ DRWPass *image_empties_ps;
+ DRWPass *image_empties_back_ps;
+ DRWPass *image_empties_blend_ps;
+ DRWPass *image_empties_front_ps;
+ DRWPass *image_foreground_ps;
+ DRWPass *metaball_ps[2];
+ DRWPass *motion_paths_ps;
+ DRWPass *outlines_prepass_ps;
+ DRWPass *outlines_detect_ps;
+ DRWPass *outlines_expand_ps;
+ DRWPass *outlines_bleed_ps;
+ DRWPass *outlines_resolve_ps;
+ DRWPass *paint_color_ps;
+ DRWPass *paint_overlay_ps;
+ DRWPass *particle_ps;
+ DRWPass *sculpt_mask_ps;
+ DRWPass *wireframe_ps;
+ DRWPass *wireframe_xray_ps;
+} OVERLAY_PassList;
+
+/* Data used by GLSL shader. To be used as UBO. */
+typedef struct OVERLAY_ShadingData {
+ /** Grid */
+ float grid_axes[3], grid_distance;
+ float zplane_axes[3], grid_mesh_size;
+ float grid_steps[8];
+ float inv_viewport_size[2];
+ float grid_line_size;
+ int grid_flag;
+ int zpos_flag;
+ int zneg_flag;
+ /** Wireframe */
+ float wire_step_param;
+ /** Edit Curve */
+ float edit_curve_normal_length;
+ /** Edit Mesh */
+ int data_mask[4];
+} OVERLAY_ShadingData;
+
+typedef struct OVERLAY_ExtraCallBuffers {
+ DRWCallBuffer *camera_frame;
+ DRWCallBuffer *camera_tria[2];
+ DRWCallBuffer *camera_distances;
+ DRWCallBuffer *camera_volume;
+ DRWCallBuffer *camera_volume_frame;
+
+ DRWCallBuffer *center_active;
+ DRWCallBuffer *center_selected;
+ DRWCallBuffer *center_deselected;
+ DRWCallBuffer *center_selected_lib;
+ DRWCallBuffer *center_deselected_lib;
+
+ DRWCallBuffer *empty_axes;
+ DRWCallBuffer *empty_capsule_body;
+ DRWCallBuffer *empty_capsule_cap;
+ DRWCallBuffer *empty_circle;
+ DRWCallBuffer *empty_cone;
+ DRWCallBuffer *empty_cube;
+ DRWCallBuffer *empty_cylinder;
+ DRWCallBuffer *empty_image_frame;
+ DRWCallBuffer *empty_plain_axes;
+ DRWCallBuffer *empty_single_arrow;
+ DRWCallBuffer *empty_sphere;
+ DRWCallBuffer *empty_sphere_solid;
+
+ DRWCallBuffer *extra_dashed_lines;
+ DRWCallBuffer *extra_lines;
+
+ DRWCallBuffer *field_curve;
+ DRWCallBuffer *field_force;
+ DRWCallBuffer *field_vortex;
+ DRWCallBuffer *field_wind;
+ DRWCallBuffer *field_cone_limit;
+ DRWCallBuffer *field_sphere_limit;
+ DRWCallBuffer *field_tube_limit;
+
+ DRWCallBuffer *groundline;
+
+ DRWCallBuffer *light_point;
+ DRWCallBuffer *light_sun;
+ DRWCallBuffer *light_spot;
+ DRWCallBuffer *light_spot_cone_back;
+ DRWCallBuffer *light_spot_cone_front;
+ DRWCallBuffer *light_area[2];
+
+ DRWCallBuffer *origin_xform;
+
+ DRWCallBuffer *probe_planar;
+ DRWCallBuffer *probe_cube;
+ DRWCallBuffer *probe_grid;
+
+ DRWCallBuffer *speaker;
+
+ DRWShadingGroup *extra_wire;
+ DRWShadingGroup *extra_loose_points;
+} OVERLAY_ExtraCallBuffers;
+
+typedef struct OVERLAY_ArmatureCallBuffers {
+ DRWCallBuffer *box_outline;
+ DRWCallBuffer *box_solid;
+
+ DRWCallBuffer *dof_lines;
+ DRWCallBuffer *dof_sphere;
+
+ DRWCallBuffer *envelope_distance;
+ DRWCallBuffer *envelope_outline;
+ DRWCallBuffer *envelope_solid;
+
+ DRWCallBuffer *octa_outline;
+ DRWCallBuffer *octa_solid;
+
+ DRWCallBuffer *point_outline;
+ DRWCallBuffer *point_solid;
+
+ DRWCallBuffer *stick;
+
+ DRWCallBuffer *wire;
+
+ DRWShadingGroup *custom_solid;
+ DRWShadingGroup *custom_outline;
+ GHash *custom_shapes_ghash;
+} OVERLAY_ArmatureCallBuffers;
+
+typedef struct OVERLAY_PrivateData {
+ DRWShadingGroup *armature_bone_select_act_grp;
+ DRWShadingGroup *armature_bone_select_grp;
+ DRWShadingGroup *edit_curve_normal_grp[2];
+ DRWShadingGroup *edit_curve_wire_grp[2];
+ DRWShadingGroup *edit_curve_handle_grp;
+ DRWShadingGroup *edit_curve_points_grp;
+ DRWShadingGroup *edit_lattice_points_grp;
+ DRWShadingGroup *edit_lattice_wires_grp;
+ DRWShadingGroup *edit_mesh_depth_grp[2];
+ DRWShadingGroup *edit_mesh_faces_grp[2];
+ DRWShadingGroup *edit_mesh_faces_cage_grp[2];
+ DRWShadingGroup *edit_mesh_verts_grp[2];
+ DRWShadingGroup *edit_mesh_edges_grp[2];
+ DRWShadingGroup *edit_mesh_facedots_grp[2];
+ DRWShadingGroup *edit_mesh_skin_roots_grp[2];
+ DRWShadingGroup *edit_mesh_normals_grp;
+ DRWShadingGroup *edit_mesh_analysis_grp;
+ DRWShadingGroup *edit_mesh_weight_grp;
+ DRWShadingGroup *edit_particle_strand_grp;
+ DRWShadingGroup *edit_particle_point_grp;
+ DRWShadingGroup *edit_text_overlay_grp;
+ DRWShadingGroup *edit_text_wire_grp[2];
+ DRWShadingGroup *facing_grp;
+ DRWShadingGroup *motion_path_lines_grp;
+ DRWShadingGroup *motion_path_points_grp;
+ DRWShadingGroup *outlines_active_grp;
+ DRWShadingGroup *outlines_select_grp;
+ DRWShadingGroup *outlines_select_dupli_grp;
+ DRWShadingGroup *outlines_transform_grp;
+ DRWShadingGroup *outlines_probe_transform_grp;
+ DRWShadingGroup *outlines_probe_select_grp;
+ DRWShadingGroup *outlines_probe_select_dupli_grp;
+ DRWShadingGroup *outlines_probe_active_grp;
+ DRWShadingGroup *outlines_probe_grid_grp;
+ DRWShadingGroup *paint_surf_grp;
+ DRWShadingGroup *paint_wire_grp;
+ DRWShadingGroup *paint_wire_selected_grp;
+ DRWShadingGroup *paint_point_grp;
+ DRWShadingGroup *paint_face_grp;
+ DRWShadingGroup *particle_dots_grp;
+ DRWShadingGroup *particle_shapes_grp;
+ DRWShadingGroup *sculpt_mask_grp;
+ DRWShadingGroup *wires_grp[2][2]; /* With and without coloring. */
+ DRWShadingGroup *wires_all_grp[2][2]; /* With and without coloring. */
+ DRWShadingGroup *wires_sculpt_grp[2];
+
+ DRWView *view_default;
+ DRWView *view_wires;
+ DRWView *view_edit_faces;
+ DRWView *view_edit_faces_cage;
+ DRWView *view_edit_edges;
+ DRWView *view_edit_verts;
+ DRWView *view_reference_images;
+
+ /** TODO get rid of this. */
+ ListBase smoke_domains;
+ ListBase bg_movie_clips;
+
+ /** Two instances for in_front option and without. */
+ OVERLAY_ExtraCallBuffers extra_call_buffers[2];
+
+ OVERLAY_ArmatureCallBuffers armature_call_buffers[2];
+
+ View3DOverlay overlay;
+ enum eContextObjectMode ctx_mode;
+ bool clear_in_front;
+ bool wireframe_mode;
+ bool hide_overlays;
+ bool xray_enabled;
+ bool xray_enabled_and_not_wire;
+ short v3d_flag; /* TODO move to View3DOverlay */
+ short v3d_gridflag; /* TODO move to View3DOverlay */
+ DRWState clipping_state;
+ OVERLAY_ShadingData shdata;
+
+ struct {
+ short sample;
+ short target_sample;
+ float prev_persmat[4][4];
+ bool enabled;
+ } antialiasing;
+ struct {
+ bool show_handles;
+ } edit_curve;
+ struct {
+ int ghost_ob;
+ int edit_ob;
+ bool do_zbufclip;
+ bool do_faces;
+ bool do_edges;
+ bool select_vert;
+ bool select_face;
+ bool select_edge;
+ int flag; /** Copy of v3d->overlay.edit_flag. */
+ } edit_mesh;
+ struct {
+ bool use_weight;
+ int select_mode;
+ } edit_particle;
+ struct {
+ bool transparent;
+ bool show_relations;
+ bool do_pose_fade_geom;
+ } armature;
+ struct {
+ DRWCallBuffer *handle[2];
+ } mball;
+} OVERLAY_PrivateData; /* Transient data */
+
+typedef struct OVERLAY_StorageList {
+ struct OVERLAY_PrivateData *pd;
+} OVERLAY_StorageList;
+
+typedef struct OVERLAY_Data {
+ void *engine_type;
+ OVERLAY_FramebufferList *fbl;
+ OVERLAY_TextureList *txl;
+ OVERLAY_PassList *psl;
+ OVERLAY_StorageList *stl;
+} OVERLAY_Data;
+
+typedef struct OVERLAY_DupliData {
+ DRWShadingGroup *wire_shgrp;
+ DRWShadingGroup *outline_shgrp;
+ DRWShadingGroup *extra_shgrp;
+ struct GPUBatch *wire_geom;
+ struct GPUBatch *outline_geom;
+ struct GPUBatch *extra_geom;
+ short base_flag;
+} OVERLAY_DupliData;
+
+typedef struct BoneInstanceData {
+ /* Keep sync with bone instance vertex format (OVERLAY_InstanceFormats) */
+ union {
+ float mat[4][4];
+ struct {
+ float _pad0[3], color_hint_a;
+ float _pad1[3], color_hint_b;
+ float _pad2[3], color_a;
+ float _pad3[3], color_b;
+ };
+ struct {
+ float _pad00[3], amin_a;
+ float _pad01[3], amin_b;
+ float _pad02[3], amax_a;
+ float _pad03[3], amax_b;
+ };
+ };
+} BoneInstanceData;
+
+typedef struct OVERLAY_InstanceFormats {
+ struct GPUVertFormat *instance_pos;
+ struct GPUVertFormat *instance_extra;
+ struct GPUVertFormat *instance_bone;
+ struct GPUVertFormat *instance_bone_outline;
+ struct GPUVertFormat *instance_bone_envelope;
+ struct GPUVertFormat *instance_bone_envelope_distance;
+ struct GPUVertFormat *instance_bone_envelope_outline;
+ struct GPUVertFormat *instance_bone_stick;
+ struct GPUVertFormat *pos;
+ struct GPUVertFormat *pos_color;
+ struct GPUVertFormat *wire_extra;
+} OVERLAY_InstanceFormats;
+
+/* Pack data into the last row of the 4x4 matrix. It will be decoded by the vertex shader. */
+BLI_INLINE void pack_data_in_mat4(
+ float rmat[4][4], const float mat[4][4], float a, float b, float c, float d)
+{
+ copy_m4_m4(rmat, mat);
+ rmat[0][3] = a;
+ rmat[1][3] = b;
+ rmat[2][3] = c;
+ rmat[3][3] = d;
+}
+
+BLI_INLINE void pack_v4_in_mat4(float rmat[4][4], const float mat[4][4], const float v[4])
+{
+ pack_data_in_mat4(rmat, mat, v[0], v[1], v[2], v[3]);
+}
+
+BLI_INLINE void pack_fl_in_mat4(float rmat[4][4], const float mat[4][4], float a)
+{
+ copy_m4_m4(rmat, mat);
+ rmat[3][3] = a;
+}
+
+void OVERLAY_antialiasing_reset(OVERLAY_Data *vedata);
+void OVERLAY_antialiasing_init(OVERLAY_Data *vedata);
+void OVERLAY_antialiasing_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_antialiasing_cache_finish(OVERLAY_Data *vedata);
+void OVERLAY_antialiasing_start(OVERLAY_Data *vedata);
+void OVERLAY_antialiasing_end(OVERLAY_Data *vedata);
+
+bool OVERLAY_armature_is_pose_mode(Object *ob, const struct DRWContextState *draw_ctx);
+void OVERLAY_armature_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_armature_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_armature_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_pose_armature_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_armature_cache_finish(OVERLAY_Data *vedata);
+void OVERLAY_armature_draw(OVERLAY_Data *vedata);
+void OVERLAY_armature_in_front_draw(OVERLAY_Data *vedata);
+void OVERLAY_pose_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_pose_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_bone_instance_data_set_color_hint(BoneInstanceData *data, const float hint_color[4]);
+void OVERLAY_bone_instance_data_set_color(BoneInstanceData *data, const float bone_color[4]);
+
+void OVERLAY_edit_curve_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_curve_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_curve_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_surf_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_curve_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_edit_lattice_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_lattice_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_edit_text_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_text_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_text_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_edit_mesh_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_mesh_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_mesh_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_edit_particle_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_particle_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_edit_particle_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_extra_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_extra_draw(OVERLAY_Data *vedata);
+void OVERLAY_extra_in_front_draw(OVERLAY_Data *vedata);
+void OVERLAY_extra_centers_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_camera_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_empty_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_speaker_cache_populate(OVERLAY_Data *vedata, Object *ob);
+
+OVERLAY_ExtraCallBuffers *OVERLAY_extra_call_buffer_get(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_extra_line_dashed(OVERLAY_ExtraCallBuffers *cb,
+ const float start[3],
+ const float end[3],
+ const float color[4]);
+void OVERLAY_extra_line(OVERLAY_ExtraCallBuffers *cb,
+ const float start[3],
+ const float end[3],
+ const int color_id);
+void OVERLAY_empty_shape(OVERLAY_ExtraCallBuffers *cb,
+ const float mat[4][4],
+ const float draw_size,
+ const char draw_type,
+ const float color[4]);
+void OVERLAY_extra_loose_points(OVERLAY_ExtraCallBuffers *cb,
+ struct GPUBatch *geom,
+ const float mat[4][4],
+ const float color[4]);
+void OVERLAY_extra_wire(OVERLAY_ExtraCallBuffers *cb,
+ struct GPUBatch *geom,
+ const float mat[4][4],
+ const float color[4]);
+
+void OVERLAY_facing_init(OVERLAY_Data *vedata);
+void OVERLAY_facing_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_facing_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_facing_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_grid_init(OVERLAY_Data *vedata);
+void OVERLAY_grid_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_grid_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_image_init(OVERLAY_Data *vedata);
+void OVERLAY_image_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_image_camera_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_image_cache_finish(OVERLAY_Data *vedata);
+void OVERLAY_image_draw(OVERLAY_Data *vedata);
+void OVERLAY_image_in_front_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_metaball_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_edit_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_metaball_draw(OVERLAY_Data *vedata);
+void OVERLAY_metaball_in_front_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_motion_path_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_motion_path_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_motion_path_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_outline_init(OVERLAY_Data *vedata);
+void OVERLAY_outline_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
+ Object *ob,
+ OVERLAY_DupliData *dupli,
+ bool init_dupli);
+void OVERLAY_outline_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_paint_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_paint_texture_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_paint_vertex_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_paint_weight_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_paint_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_particle_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_particle_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_particle_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_sculpt_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_sculpt_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_sculpt_draw(OVERLAY_Data *vedata);
+
+void OVERLAY_wireframe_init(OVERLAY_Data *vedata);
+void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
+ Object *ob,
+ OVERLAY_DupliData *dupli,
+ bool init_dupli);
+void OVERLAY_wireframe_draw(OVERLAY_Data *vedata);
+void OVERLAY_wireframe_in_front_draw(OVERLAY_Data *vedata);
+
+GPUShader *OVERLAY_shader_antialiasing(void);
+GPUShader *OVERLAY_shader_armature_degrees_of_freedom(void);
+GPUShader *OVERLAY_shader_armature_envelope(bool use_outline);
+GPUShader *OVERLAY_shader_armature_shape(bool use_outline);
+GPUShader *OVERLAY_shader_armature_sphere(bool use_outline);
+GPUShader *OVERLAY_shader_armature_stick(void);
+GPUShader *OVERLAY_shader_armature_wire(void);
+GPUShader *OVERLAY_shader_depth_only(void);
+GPUShader *OVERLAY_shader_edit_curve_handle(void);
+GPUShader *OVERLAY_shader_edit_curve_point(void);
+GPUShader *OVERLAY_shader_edit_curve_wire(void);
+GPUShader *OVERLAY_shader_edit_lattice_point(void);
+GPUShader *OVERLAY_shader_edit_lattice_wire(void);
+GPUShader *OVERLAY_shader_edit_mesh_analysis(void);
+GPUShader *OVERLAY_shader_edit_mesh_edge(bool use_flat_interp);
+GPUShader *OVERLAY_shader_edit_mesh_face(void);
+GPUShader *OVERLAY_shader_edit_mesh_facedot(void);
+GPUShader *OVERLAY_shader_edit_mesh_normal(void);
+GPUShader *OVERLAY_shader_edit_mesh_skin_root(void);
+GPUShader *OVERLAY_shader_edit_mesh_vert(void);
+GPUShader *OVERLAY_shader_edit_particle_strand(void);
+GPUShader *OVERLAY_shader_edit_particle_point(void);
+GPUShader *OVERLAY_shader_extra(void);
+GPUShader *OVERLAY_shader_extra_groundline(void);
+GPUShader *OVERLAY_shader_extra_wire(bool use_object);
+GPUShader *OVERLAY_shader_extra_loose_point(void);
+GPUShader *OVERLAY_shader_extra_point(void);
+GPUShader *OVERLAY_shader_facing(void);
+GPUShader *OVERLAY_shader_grid(void);
+GPUShader *OVERLAY_shader_image(void);
+GPUShader *OVERLAY_shader_motion_path_line(void);
+GPUShader *OVERLAY_shader_motion_path_vert(void);
+GPUShader *OVERLAY_shader_uniform_color(void);
+GPUShader *OVERLAY_shader_outline_prepass(bool use_wire);
+GPUShader *OVERLAY_shader_outline_prepass_grid(void);
+GPUShader *OVERLAY_shader_outline_resolve(void);
+GPUShader *OVERLAY_shader_outline_expand(bool high_dpi);
+GPUShader *OVERLAY_shader_outline_detect(bool use_wire);
+GPUShader *OVERLAY_shader_paint_face(void);
+GPUShader *OVERLAY_shader_paint_point(void);
+GPUShader *OVERLAY_shader_paint_texture(void);
+GPUShader *OVERLAY_shader_paint_vertcol(void);
+GPUShader *OVERLAY_shader_paint_weight(void);
+GPUShader *OVERLAY_shader_paint_wire(void);
+GPUShader *OVERLAY_shader_particle_dot(void);
+GPUShader *OVERLAY_shader_particle_shape(void);
+GPUShader *OVERLAY_shader_sculpt_mask(void);
+GPUShader *OVERLAY_shader_volume_velocity(bool use_needle);
+GPUShader *OVERLAY_shader_wireframe(void);
+GPUShader *OVERLAY_shader_wireframe_select(void);
+
+OVERLAY_InstanceFormats *OVERLAY_shader_instance_formats_get(void);
+
+void OVERLAY_shader_free(void);
+
+#endif /* __OVERLAY_PRIVATE_H__ */ \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/overlay_sculpt.c b/source/blender/draw/engines/overlay/overlay_sculpt.c
new file mode 100644
index 00000000000..3b7f12ed804
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_sculpt.c
@@ -0,0 +1,65 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "overlay_private.h"
+
+#include "BKE_pbvh.h"
+#include "BKE_paint.h"
+#include "BKE_subdiv_ccg.h"
+
+void OVERLAY_sculpt_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DRWShadingGroup *grp;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->sculpt_mask_ps, state | pd->clipping_state);
+
+ GPUShader *sh = OVERLAY_shader_sculpt_mask();
+ pd->sculpt_mask_grp = grp = DRW_shgroup_create(sh, psl->sculpt_mask_ps);
+ DRW_shgroup_uniform_float_copy(grp, "maskOpacity", pd->overlay.sculpt_mode_mask_opacity);
+}
+
+void OVERLAY_sculpt_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ const bool use_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
+
+ if (use_pbvh || !ob->sculpt->deform_modifiers_active || ob->sculpt->shapekey_active) {
+ if (pbvh_has_mask(pbvh)) {
+ DRW_shgroup_call_sculpt(pd->sculpt_mask_grp, ob, false, true, false);
+ }
+ }
+}
+
+void OVERLAY_sculpt_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->sculpt_mask_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c
new file mode 100644
index 00000000000..fa495d153e9
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_shader.c
@@ -0,0 +1,1337 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "GPU_shader.h"
+
+#include "UI_resources.h"
+
+#include "overlay_private.h"
+
+extern char datatoc_antialiasing_frag_glsl[];
+extern char datatoc_antialiasing_vert_glsl[];
+extern char datatoc_armature_dof_vert_glsl[];
+extern char datatoc_armature_envelope_distance_frag_glsl[];
+extern char datatoc_armature_envelope_outline_vert_glsl[];
+extern char datatoc_armature_envelope_solid_frag_glsl[];
+extern char datatoc_armature_envelope_solid_vert_glsl[];
+extern char datatoc_armature_shape_outline_geom_glsl[];
+extern char datatoc_armature_shape_outline_vert_glsl[];
+extern char datatoc_armature_shape_solid_frag_glsl[];
+extern char datatoc_armature_shape_solid_vert_glsl[];
+extern char datatoc_armature_sphere_outline_vert_glsl[];
+extern char datatoc_armature_sphere_solid_frag_glsl[];
+extern char datatoc_armature_sphere_solid_vert_glsl[];
+extern char datatoc_armature_stick_frag_glsl[];
+extern char datatoc_armature_stick_vert_glsl[];
+extern char datatoc_armature_wire_vert_glsl[];
+extern char datatoc_depth_only_vert_glsl[];
+extern char datatoc_edit_curve_handle_geom_glsl[];
+extern char datatoc_edit_curve_handle_vert_glsl[];
+extern char datatoc_edit_curve_point_vert_glsl[];
+extern char datatoc_edit_curve_wire_vert_glsl[];
+extern char datatoc_edit_lattice_point_vert_glsl[];
+extern char datatoc_edit_lattice_wire_vert_glsl[];
+extern char datatoc_edit_mesh_common_lib_glsl[];
+extern char datatoc_edit_mesh_frag_glsl[];
+extern char datatoc_edit_mesh_geom_glsl[];
+extern char datatoc_edit_mesh_vert_glsl[];
+extern char datatoc_edit_mesh_normal_vert_glsl[];
+extern char datatoc_edit_mesh_skin_root_vert_glsl[];
+extern char datatoc_edit_mesh_analysis_vert_glsl[];
+extern char datatoc_edit_mesh_analysis_frag_glsl[];
+extern char datatoc_edit_particle_strand_vert_glsl[];
+extern char datatoc_edit_particle_point_vert_glsl[];
+extern char datatoc_extra_frag_glsl[];
+extern char datatoc_extra_vert_glsl[];
+extern char datatoc_extra_groundline_vert_glsl[];
+extern char datatoc_extra_loose_point_vert_glsl[];
+extern char datatoc_extra_loose_point_frag_glsl[];
+extern char datatoc_extra_point_vert_glsl[];
+extern char datatoc_extra_wire_frag_glsl[];
+extern char datatoc_extra_wire_vert_glsl[];
+extern char datatoc_facing_frag_glsl[];
+extern char datatoc_facing_vert_glsl[];
+extern char datatoc_grid_frag_glsl[];
+extern char datatoc_grid_vert_glsl[];
+extern char datatoc_image_frag_glsl[];
+extern char datatoc_image_vert_glsl[];
+extern char datatoc_motion_path_line_vert_glsl[];
+extern char datatoc_motion_path_line_geom_glsl[];
+extern char datatoc_motion_path_point_vert_glsl[];
+extern char datatoc_outline_detect_frag_glsl[];
+extern char datatoc_outline_expand_frag_glsl[];
+extern char datatoc_outline_prepass_frag_glsl[];
+extern char datatoc_outline_prepass_geom_glsl[];
+extern char datatoc_outline_prepass_vert_glsl[];
+extern char datatoc_outline_lightprobe_grid_vert_glsl[];
+extern char datatoc_outline_resolve_frag_glsl[];
+extern char datatoc_paint_face_vert_glsl[];
+extern char datatoc_paint_point_vert_glsl[];
+extern char datatoc_paint_texture_frag_glsl[];
+extern char datatoc_paint_texture_vert_glsl[];
+extern char datatoc_paint_vertcol_frag_glsl[];
+extern char datatoc_paint_vertcol_vert_glsl[];
+extern char datatoc_paint_weight_frag_glsl[];
+extern char datatoc_paint_weight_vert_glsl[];
+extern char datatoc_paint_wire_vert_glsl[];
+extern char datatoc_particle_vert_glsl[];
+extern char datatoc_particle_frag_glsl[];
+extern char datatoc_sculpt_mask_vert_glsl[];
+extern char datatoc_volume_velocity_vert_glsl[];
+extern char datatoc_wireframe_vert_glsl[];
+extern char datatoc_wireframe_geom_glsl[];
+extern char datatoc_wireframe_frag_glsl[];
+
+extern char datatoc_gpu_shader_depth_only_frag_glsl[];
+extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
+extern char datatoc_gpu_shader_flat_color_frag_glsl[];
+extern char datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl[];
+extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
+
+extern char datatoc_common_colormanagement_lib_glsl[];
+extern char datatoc_common_fullscreen_vert_glsl[];
+extern char datatoc_common_fxaa_lib_glsl[];
+extern char datatoc_common_smaa_lib_glsl[];
+extern char datatoc_common_globals_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+
+typedef struct OVERLAY_Shaders {
+ GPUShader *antialiasing;
+ GPUShader *armature_dof;
+ GPUShader *armature_envelope_outline;
+ GPUShader *armature_envelope_solid;
+ GPUShader *armature_shape_outline;
+ GPUShader *armature_shape_solid;
+ GPUShader *armature_sphere_outline;
+ GPUShader *armature_sphere_solid;
+ GPUShader *armature_stick;
+ GPUShader *armature_wire;
+ GPUShader *depth_only;
+ GPUShader *edit_curve_handle;
+ GPUShader *edit_curve_point;
+ GPUShader *edit_curve_wire;
+ GPUShader *edit_lattice_point;
+ GPUShader *edit_lattice_wire;
+ GPUShader *edit_mesh_vert;
+ GPUShader *edit_mesh_edge;
+ GPUShader *edit_mesh_edge_flat;
+ GPUShader *edit_mesh_face;
+ GPUShader *edit_mesh_facedot;
+ GPUShader *edit_mesh_skin_root;
+ GPUShader *edit_mesh_vnormals;
+ GPUShader *edit_mesh_normals;
+ GPUShader *edit_mesh_fnormals;
+ GPUShader *edit_mesh_analysis;
+ GPUShader *edit_particle_strand;
+ GPUShader *edit_particle_point;
+ GPUShader *extra;
+ GPUShader *extra_groundline;
+ GPUShader *extra_wire[2];
+ GPUShader *extra_point;
+ GPUShader *extra_loose_point;
+ GPUShader *facing;
+ GPUShader *grid;
+ GPUShader *image;
+ GPUShader *motion_path_line;
+ GPUShader *motion_path_vert;
+ GPUShader *outline_prepass;
+ GPUShader *outline_prepass_wire;
+ GPUShader *outline_prepass_lightprobe_grid;
+ GPUShader *outline_resolve;
+ GPUShader *outline_fade;
+ GPUShader *outline_fade_large;
+ GPUShader *outline_detect;
+ GPUShader *outline_detect_wire;
+ GPUShader *paint_face;
+ GPUShader *paint_point;
+ GPUShader *paint_texture;
+ GPUShader *paint_vertcol;
+ GPUShader *paint_weight;
+ GPUShader *paint_wire;
+ GPUShader *particle_dot;
+ GPUShader *particle_shape;
+ GPUShader *sculpt_mask;
+ GPUShader *uniform_color;
+ GPUShader *volume_velocity_needle_sh;
+ GPUShader *volume_velocity_sh;
+ GPUShader *wireframe_select;
+ GPUShader *wireframe;
+} OVERLAY_Shaders;
+
+static struct {
+ OVERLAY_Shaders sh_data[GPU_SHADER_CFG_LEN];
+} e_data = {{{NULL}}};
+
+GPUShader *OVERLAY_shader_antialiasing(void)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (!sh_data->antialiasing) {
+ sh_data->antialiasing = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_antialiasing_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_antialiasing_frag_glsl,
+ NULL},
+ .defs = (const char *[]){NULL},
+ });
+ }
+ return sh_data->antialiasing;
+}
+
+GPUShader *OVERLAY_shader_depth_only(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->depth_only) {
+ sh_data->depth_only = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_depth_only_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_depth_only_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->depth_only;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_vert(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_mesh_vert) {
+ sh_data->edit_mesh_vert = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_common_lib_glsl,
+ datatoc_edit_mesh_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define VERT\n", NULL},
+ });
+ }
+ return sh_data->edit_mesh_vert;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_edge(bool use_flat_interp)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ GPUShader **sh = use_flat_interp ? &sh_data->edit_mesh_edge_flat : &sh_data->edit_mesh_edge;
+ if (*sh == NULL) {
+ /* Use geometry shader to draw edge wire-frame. This ensure us
+ * the same result across platforms and more flexibility.
+ * But we pay the cost of running a geometry shader.
+ * In the future we might consider using only the vertex shader
+ * and loading data manually with buffer textures. */
+ const bool use_geom_shader = true;
+ const bool use_smooth_wires = (U.gpu_flag & USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE) == 0;
+ const char *geom_sh_code[] = {use_geom_shader ? sh_cfg->lib : NULL,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_geom_glsl,
+ NULL};
+ const char *vert_sh_code[] = {sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_common_lib_glsl,
+ datatoc_edit_mesh_vert_glsl,
+ NULL};
+ const char *frag_sh_code[] = {sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_common_lib_glsl,
+ datatoc_edit_mesh_frag_glsl,
+ NULL};
+ const char *defs[] = {sh_cfg->def,
+ use_geom_shader ? "#define USE_GEOM_SHADER\n" : "",
+ use_smooth_wires ? "#define USE_SMOOTH_WIRE\n" : "",
+ use_flat_interp ? "#define FLAT\n" : "",
+ "#define EDGE\n",
+ NULL};
+
+ *sh = GPU_shader_create_from_arrays({
+ .vert = vert_sh_code,
+ .frag = frag_sh_code,
+ .geom = geom_sh_code,
+ .defs = defs,
+ });
+ }
+ return *sh;
+}
+
+GPUShader *OVERLAY_shader_armature_sphere(bool use_outline)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ const char extensions[] = "#extension GL_ARB_conservative_depth : enable\n";
+ if (use_outline && !sh_data->armature_sphere_outline) {
+ sh_data->armature_sphere_outline = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_sphere_outline_vert_glsl,
+ NULL},
+ .frag = (const char *[]){extensions,
+ datatoc_common_view_lib_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ else if (!sh_data->armature_sphere_solid) {
+ sh_data->armature_sphere_solid = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_sphere_solid_vert_glsl,
+ NULL},
+ .frag = (const char *[]){extensions,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_sphere_solid_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return use_outline ? sh_data->armature_sphere_outline : sh_data->armature_sphere_solid;
+}
+
+GPUShader *OVERLAY_shader_armature_shape(bool use_outline)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (use_outline && !sh_data->armature_shape_outline) {
+ sh_data->armature_shape_outline = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_shape_outline_vert_glsl,
+ NULL},
+ .geom = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_shape_outline_geom_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ else if (!sh_data->armature_shape_solid) {
+ sh_data->armature_shape_solid = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_shape_solid_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_armature_shape_solid_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return use_outline ? sh_data->armature_shape_outline : sh_data->armature_shape_solid;
+}
+
+GPUShader *OVERLAY_shader_armature_envelope(bool use_outline)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (use_outline && !sh_data->armature_envelope_outline) {
+ sh_data->armature_envelope_outline = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_envelope_outline_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ else if (!sh_data->armature_envelope_solid) {
+ sh_data->armature_envelope_solid = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_envelope_solid_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_armature_envelope_solid_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return use_outline ? sh_data->armature_envelope_outline : sh_data->armature_envelope_solid;
+}
+
+GPUShader *OVERLAY_shader_armature_stick(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->armature_stick) {
+ sh_data->armature_stick = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_stick_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_armature_stick_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->armature_stick;
+}
+
+GPUShader *OVERLAY_shader_armature_degrees_of_freedom(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->armature_dof) {
+ sh_data->armature_dof = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_dof_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->armature_dof;
+}
+
+GPUShader *OVERLAY_shader_armature_wire(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->armature_wire) {
+ sh_data->armature_wire = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_armature_wire_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->armature_wire;
+}
+
+GPUShader *OVERLAY_shader_edit_curve_handle(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_curve_handle) {
+ sh_data->edit_curve_handle = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_curve_handle_vert_glsl,
+ NULL},
+ .geom = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_curve_handle_geom_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_curve_handle;
+}
+
+GPUShader *OVERLAY_shader_edit_curve_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_curve_point) {
+ sh_data->edit_curve_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_curve_point_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_curve_point;
+}
+
+GPUShader *OVERLAY_shader_edit_curve_wire(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_curve_wire) {
+ sh_data->edit_curve_wire = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_curve_wire_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define IN_PLACE_INSTANCES\n", NULL},
+ });
+ }
+ return sh_data->edit_curve_wire;
+}
+
+GPUShader *OVERLAY_shader_edit_lattice_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_lattice_point) {
+ sh_data->edit_lattice_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_lattice_point_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_lattice_point;
+}
+
+GPUShader *OVERLAY_shader_edit_lattice_wire(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_lattice_wire) {
+ sh_data->edit_lattice_wire = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_lattice_wire_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_lattice_wire;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_face(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_mesh_face) {
+ sh_data->edit_mesh_face = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_common_lib_glsl,
+ datatoc_edit_mesh_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define FACE\n", NULL},
+ });
+ }
+ return sh_data->edit_mesh_face;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_facedot(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_mesh_facedot) {
+ sh_data->edit_mesh_facedot = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_common_lib_glsl,
+ datatoc_edit_mesh_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define FACEDOT\n", NULL},
+ });
+ }
+ return sh_data->edit_mesh_facedot;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_normal(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_mesh_normals) {
+ sh_data->edit_mesh_normals = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_normal_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define INSTANCED_ATTRIB\n", NULL},
+ });
+ }
+ return sh_data->edit_mesh_normals;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_analysis(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_mesh_analysis) {
+ sh_data->edit_mesh_analysis = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_analysis_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_edit_mesh_analysis_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_mesh_analysis;
+}
+
+GPUShader *OVERLAY_shader_edit_mesh_skin_root(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_mesh_skin_root) {
+ sh_data->edit_mesh_skin_root = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_mesh_skin_root_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define INSTANCED_ATTRIB\n", NULL},
+ });
+ }
+ return sh_data->edit_mesh_skin_root;
+}
+
+GPUShader *OVERLAY_shader_edit_particle_strand(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_particle_strand) {
+ sh_data->edit_particle_strand = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_particle_strand_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_particle_strand;
+}
+
+GPUShader *OVERLAY_shader_edit_particle_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_particle_point) {
+ sh_data->edit_particle_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_particle_point_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_particle_point;
+}
+
+GPUShader *OVERLAY_shader_extra(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->extra) {
+ sh_data->extra = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_extra_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->extra;
+}
+
+GPUShader *OVERLAY_shader_extra_groundline(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->extra_groundline) {
+ sh_data->extra_groundline = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_extra_groundline_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->extra_groundline;
+}
+
+GPUShader *OVERLAY_shader_extra_wire(bool use_object)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->extra_wire[use_object]) {
+ char colorids[1024];
+ /* NOTE: define all ids we need here. */
+ BLI_snprintf(colorids,
+ sizeof(colorids),
+ "#define TH_ACTIVE %d\n"
+ "#define TH_SELECT %d\n"
+ "#define TH_TRANSFORM %d\n"
+ "#define TH_WIRE %d\n"
+ "#define TH_CAMERA_PATH %d\n",
+ TH_ACTIVE,
+ TH_SELECT,
+ TH_TRANSFORM,
+ TH_WIRE,
+ TH_CAMERA_PATH);
+ sh_data->extra_wire[use_object] = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_extra_wire_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_wire_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def,
+ colorids,
+ (use_object) ? "#define OBJECT_WIRE \n" : NULL,
+ NULL},
+ });
+ }
+ return sh_data->extra_wire[use_object];
+}
+
+GPUShader *OVERLAY_shader_extra_loose_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->extra_loose_point) {
+ sh_data->extra_loose_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_extra_loose_point_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_extra_loose_point_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->extra_loose_point;
+}
+
+GPUShader *OVERLAY_shader_extra_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->extra_point) {
+ sh_data->extra_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_extra_point_vert_glsl,
+ NULL},
+ .frag =
+ (const char *[]){datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->extra_point;
+}
+
+GPUShader *OVERLAY_shader_facing(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->facing) {
+ sh_data->facing = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_facing_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_facing_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->facing;
+}
+
+GPUShader *OVERLAY_shader_grid(void)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (!sh_data->grid) {
+ sh_data->grid = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_grid_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_grid_frag_glsl,
+ NULL},
+ });
+ }
+ return sh_data->grid;
+}
+
+GPUShader *OVERLAY_shader_image(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->image) {
+ sh_data->image = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_image_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
+ datatoc_image_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->image;
+}
+
+GPUShader *OVERLAY_shader_motion_path_line(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->motion_path_line) {
+ sh_data->motion_path_line = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_motion_path_line_vert_glsl,
+ NULL},
+ .geom = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_motion_path_line_geom_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->motion_path_line;
+}
+
+GPUShader *OVERLAY_shader_motion_path_vert(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->motion_path_vert) {
+ sh_data->motion_path_vert = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_motion_path_point_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->motion_path_vert;
+}
+
+GPUShader *OVERLAY_shader_outline_prepass(bool use_wire)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (use_wire && !sh_data->outline_prepass_wire) {
+ sh_data->outline_prepass_wire = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_outline_prepass_vert_glsl,
+ NULL},
+ .geom = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_outline_prepass_geom_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_outline_prepass_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define USE_GEOM\n", NULL},
+ });
+ }
+ else if (!sh_data->outline_prepass) {
+ sh_data->outline_prepass = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_outline_prepass_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_outline_prepass_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return use_wire ? sh_data->outline_prepass_wire : sh_data->outline_prepass;
+}
+
+GPUShader *OVERLAY_shader_outline_prepass_grid(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->outline_prepass_lightprobe_grid) {
+ sh_data->outline_prepass_lightprobe_grid = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_common_globals_lib_glsl,
+ datatoc_outline_lightprobe_grid_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_outline_prepass_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->outline_prepass_lightprobe_grid;
+}
+
+GPUShader *OVERLAY_shader_outline_resolve(void)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (!sh_data->outline_resolve) {
+ sh_data->outline_resolve = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
+ NULL,
+ datatoc_outline_resolve_frag_glsl,
+ datatoc_common_fxaa_lib_glsl,
+ "#define FXAA_ALPHA\n"
+ "#define USE_FXAA\n");
+ }
+ return sh_data->outline_resolve;
+}
+
+GPUShader *OVERLAY_shader_outline_expand(bool high_dpi)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (high_dpi && !sh_data->outline_fade_large) {
+ sh_data->outline_fade_large = DRW_shader_create_fullscreen(datatoc_outline_expand_frag_glsl,
+ "#define LARGE_OUTLINE\n");
+ }
+ else if (!sh_data->outline_fade) {
+ sh_data->outline_fade = DRW_shader_create_fullscreen(datatoc_outline_expand_frag_glsl, NULL);
+ }
+ return (high_dpi) ? sh_data->outline_fade_large : sh_data->outline_fade;
+}
+
+GPUShader *OVERLAY_shader_outline_detect(bool use_wire)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (use_wire && !sh_data->outline_detect_wire) {
+ sh_data->outline_detect_wire = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
+ NULL,
+ datatoc_outline_detect_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define WIRE\n");
+ }
+ else if (!sh_data->outline_detect) {
+ sh_data->outline_detect = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl,
+ NULL,
+ datatoc_outline_detect_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ NULL);
+ }
+ return (use_wire) ? sh_data->outline_detect_wire : sh_data->outline_detect;
+}
+
+GPUShader *OVERLAY_shader_paint_face(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->paint_face) {
+ sh_data->paint_face = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_paint_face_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->paint_face;
+}
+
+GPUShader *OVERLAY_shader_paint_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->paint_point) {
+ sh_data->paint_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_paint_point_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->paint_point;
+}
+
+GPUShader *OVERLAY_shader_paint_texture(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->paint_texture) {
+ sh_data->paint_texture = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_paint_texture_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
+ datatoc_paint_texture_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->paint_texture;
+}
+
+GPUShader *OVERLAY_shader_paint_vertcol(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->paint_vertcol) {
+ sh_data->paint_vertcol = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_paint_vertcol_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_paint_vertcol_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->paint_vertcol;
+}
+
+GPUShader *OVERLAY_shader_paint_weight(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->paint_weight) {
+ sh_data->paint_weight = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_paint_weight_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_paint_weight_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->paint_weight;
+}
+
+GPUShader *OVERLAY_shader_paint_wire(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->paint_wire) {
+ sh_data->paint_wire = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_paint_wire_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->paint_wire;
+}
+
+GPUShader *OVERLAY_shader_particle_dot(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->particle_dot) {
+ sh_data->particle_dot = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_particle_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_particle_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define USE_DOTS\n", NULL},
+ });
+ }
+ return sh_data->particle_dot;
+}
+
+GPUShader *OVERLAY_shader_particle_shape(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->particle_shape) {
+ sh_data->particle_shape = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_particle_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define INSTANCED_ATTRIB\n", NULL},
+ });
+ }
+ return sh_data->particle_shape;
+}
+
+GPUShader *OVERLAY_shader_sculpt_mask(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->sculpt_mask) {
+ sh_data->sculpt_mask = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_sculpt_mask_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->sculpt_mask;
+}
+
+struct GPUShader *OVERLAY_shader_uniform_color(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->uniform_color) {
+ sh_data->uniform_color = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_depth_only_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->uniform_color;
+}
+
+struct GPUShader *OVERLAY_shader_volume_velocity(bool use_needle)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (use_needle && !sh_data->volume_velocity_needle_sh) {
+ sh_data->volume_velocity_needle_sh = DRW_shader_create_with_lib(
+ datatoc_volume_velocity_vert_glsl,
+ NULL,
+ datatoc_gpu_shader_flat_color_frag_glsl,
+ datatoc_common_view_lib_glsl,
+ "#define USE_NEEDLE\n");
+ }
+ else if (!sh_data->volume_velocity_sh) {
+ sh_data->volume_velocity_sh = DRW_shader_create_with_lib(
+ datatoc_volume_velocity_vert_glsl,
+ NULL,
+ datatoc_gpu_shader_flat_color_frag_glsl,
+ datatoc_common_view_lib_glsl,
+ NULL);
+ }
+ return (use_needle) ? sh_data->volume_velocity_needle_sh : sh_data->volume_velocity_sh;
+}
+
+GPUShader *OVERLAY_shader_wireframe_select(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->wireframe_select) {
+ sh_data->wireframe_select = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_common_globals_lib_glsl,
+ datatoc_gpu_shader_common_obinfos_lib_glsl,
+ datatoc_wireframe_vert_glsl,
+ NULL},
+ .geom = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_wireframe_geom_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_depth_only_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define SELECT_EDGES\n", NULL},
+ });
+ }
+ return sh_data->wireframe_select;
+}
+
+GPUShader *OVERLAY_shader_wireframe(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->wireframe) {
+ sh_data->wireframe = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_common_globals_lib_glsl,
+ datatoc_gpu_shader_common_obinfos_lib_glsl,
+ datatoc_wireframe_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_wireframe_frag_glsl, NULL},
+ /* Apple drivers does not support wide wires. Use geometry shader as a workaround. */
+#if USE_GEOM_SHADER_WORKAROUND
+ .geom = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_wireframe_geom_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define USE_GEOM\n", NULL},
+#else
+ .defs = (const char *[]){sh_cfg->def, NULL},
+#endif
+ });
+ }
+ return sh_data->wireframe;
+}
+
+static OVERLAY_InstanceFormats g_formats = {NULL};
+
+OVERLAY_InstanceFormats *OVERLAY_shader_instance_formats_get(void)
+{
+ DRW_shgroup_instance_format(g_formats.pos,
+ {
+ {"pos", DRW_ATTR_FLOAT, 3},
+ });
+ DRW_shgroup_instance_format(g_formats.pos_color,
+ {
+ {"pos", DRW_ATTR_FLOAT, 3},
+ {"color", DRW_ATTR_FLOAT, 4},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_pos,
+ {
+ {"inst_pos", DRW_ATTR_FLOAT, 3},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_extra,
+ {
+ {"color", DRW_ATTR_FLOAT, 4},
+ {"inst_obmat", DRW_ATTR_FLOAT, 16},
+ });
+ DRW_shgroup_instance_format(g_formats.wire_extra,
+ {
+ {"pos", DRW_ATTR_FLOAT, 3},
+ {"colorid", DRW_ATTR_INT, 1},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_bone,
+ {
+ {"inst_obmat", DRW_ATTR_FLOAT, 16},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_bone_stick,
+ {
+ {"boneStart", DRW_ATTR_FLOAT, 3},
+ {"boneEnd", DRW_ATTR_FLOAT, 3},
+ {"wireColor", DRW_ATTR_FLOAT, 4}, /* TODO uchar color */
+ {"boneColor", DRW_ATTR_FLOAT, 4},
+ {"headColor", DRW_ATTR_FLOAT, 4},
+ {"tailColor", DRW_ATTR_FLOAT, 4},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_bone_envelope_outline,
+ {
+ {"headSphere", DRW_ATTR_FLOAT, 4},
+ {"tailSphere", DRW_ATTR_FLOAT, 4},
+ {"outlineColorSize", DRW_ATTR_FLOAT, 4},
+ {"xAxis", DRW_ATTR_FLOAT, 3},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_bone_envelope_distance,
+ {
+ {"headSphere", DRW_ATTR_FLOAT, 4},
+ {"tailSphere", DRW_ATTR_FLOAT, 4},
+ {"xAxis", DRW_ATTR_FLOAT, 3},
+ });
+ DRW_shgroup_instance_format(g_formats.instance_bone_envelope,
+ {
+ {"headSphere", DRW_ATTR_FLOAT, 4},
+ {"tailSphere", DRW_ATTR_FLOAT, 4},
+ {"boneColor", DRW_ATTR_FLOAT, 3},
+ {"stateColor", DRW_ATTR_FLOAT, 3},
+ {"xAxis", DRW_ATTR_FLOAT, 3},
+ });
+
+ return &g_formats;
+}
+
+void OVERLAY_shader_free(void)
+{
+ for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_data_index];
+ GPUShader **sh_data_as_array = (GPUShader **)sh_data;
+ for (int i = 0; i < (sizeof(OVERLAY_Shaders) / sizeof(GPUShader *)); i++) {
+ DRW_SHADER_FREE_SAFE(sh_data_as_array[i]);
+ }
+ }
+ struct GPUVertFormat **format = (struct GPUVertFormat **)&g_formats;
+ for (int i = 0; i < sizeof(g_formats) / sizeof(void *); i++, format++) {
+ MEM_SAFE_FREE(*format);
+ }
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c
new file mode 100644
index 00000000000..d86f524cb48
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_wireframe.c
@@ -0,0 +1,231 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_editmesh.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+
+#include "BLI_hash.h"
+
+#include "GPU_shader.h"
+#include "DRW_render.h"
+
+#include "ED_view3d.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_wireframe_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ pd->view_wires = DRW_view_create_with_zoffset(pd->view_default, draw_ctx->rv3d, 0.5f);
+}
+
+void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ DRWShadingGroup *grp = NULL;
+
+ View3DShading *shading = &draw_ctx->v3d->shading;
+
+ pd->shdata.wire_step_param = pd->overlay.wireframe_threshold - 254.0f / 255.0f;
+
+ bool is_wire_shmode = (shading->type == OB_WIRE);
+ bool is_material_shmode = (shading->type > OB_SOLID);
+ bool is_object_color = is_wire_shmode && (shading->wire_color_type == V3D_SHADING_OBJECT_COLOR);
+ bool is_random_color = is_wire_shmode && (shading->wire_color_type == V3D_SHADING_RANDOM_COLOR);
+
+ const bool use_select = (DRW_state_is_select() || DRW_state_is_depth());
+ GPUShader *wires_sh = use_select ? OVERLAY_shader_wireframe_select() :
+ OVERLAY_shader_wireframe();
+
+ for (int xray = 0; xray < 2; xray++) {
+ /* Only do stencil test if stencil buffer is written by the render engine. */
+ DRWState stencil_state = is_material_shmode ? 0 : DRW_STATE_STENCIL_EQUAL;
+ DRWState state = DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR |
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRWPass *pass;
+ uint stencil_mask;
+
+ if (xray == 0) {
+ DRW_PASS_CREATE(psl->wireframe_ps, state | stencil_state | pd->clipping_state);
+ pass = psl->wireframe_ps;
+ stencil_mask = 0xFF;
+ }
+ else {
+ DRW_PASS_CREATE(psl->wireframe_xray_ps, state | pd->clipping_state);
+ pass = psl->wireframe_xray_ps;
+ stencil_mask = 0x00;
+ }
+
+ for (int use_coloring = 0; use_coloring < 2; use_coloring++) {
+ pd->wires_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "wireStepParam", pd->shdata.wire_step_param);
+ DRW_shgroup_uniform_bool_copy(grp, "useColoring", use_coloring);
+ DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
+ DRW_shgroup_uniform_bool_copy(grp, "isObjectColor", is_object_color);
+ DRW_shgroup_uniform_bool_copy(grp, "isRandomColor", is_random_color);
+ DRW_shgroup_stencil_mask(grp, stencil_mask);
+
+ pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);
+ DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 1.0f);
+ DRW_shgroup_stencil_mask(grp, stencil_mask);
+ }
+
+ pd->wires_sculpt_grp[xray] = grp = DRW_shgroup_create(wires_sh, pass);
+ DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f);
+ DRW_shgroup_uniform_bool_copy(grp, "useColoring", false);
+ DRW_shgroup_stencil_mask(grp, stencil_mask);
+ }
+}
+
+void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
+ Object *ob,
+ OVERLAY_DupliData *dupli,
+ bool init_dupli)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_PrivateData *pd = data->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES) != 0;
+ const bool is_xray = (ob->dtx & OB_DRAWXRAY) != 0;
+ const bool is_mesh = ob->type == OB_MESH;
+ const bool use_wire = (pd->overlay.flag & V3D_OVERLAY_WIREFRAMES) || (ob->dtx & OB_DRAWWIRE) ||
+ (ob->dt == OB_WIRE);
+
+ /* Fast path for duplis. */
+ if (dupli && !init_dupli) {
+ if (dupli->wire_shgrp && dupli->wire_geom) {
+ if (dupli->base_flag == ob->base_flag) {
+ DRW_shgroup_call(dupli->wire_shgrp, dupli->wire_geom, ob);
+ return;
+ }
+ }
+ else {
+ /* Nothing to draw for this dupli. */
+ return;
+ }
+ }
+
+ const bool is_edit_mode = BKE_object_is_in_editmode(ob);
+ bool has_edit_mesh_cage = false;
+ if (is_mesh && is_edit_mode) {
+ /* TODO: Should be its own function. */
+ Mesh *me = (Mesh *)ob->data;
+ BMEditMesh *embm = me->edit_mesh;
+ if (embm) {
+ has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final);
+ }
+ }
+
+ /* Don't do that in edit Mesh mode, unless there is a modifier preview. */
+ if (use_wire && (!is_mesh || (!is_edit_mode || has_edit_mesh_cage))) {
+ const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
+ !DRW_state_is_image_render();
+ const bool use_coloring = (use_wire && !is_edit_mode && !use_sculpt_pbvh &&
+ !has_edit_mesh_cage);
+ DRWShadingGroup *shgrp = NULL;
+ struct GPUBatch *geom = DRW_cache_object_face_wireframe_get(ob);
+
+ if (geom || use_sculpt_pbvh) {
+ if (use_sculpt_pbvh) {
+ shgrp = pd->wires_sculpt_grp[is_xray];
+ }
+ else if (all_wires) {
+ shgrp = pd->wires_all_grp[is_xray][use_coloring];
+ }
+ else {
+ shgrp = pd->wires_grp[is_xray][use_coloring];
+ }
+
+ if (use_sculpt_pbvh) {
+ DRW_shgroup_call_sculpt(shgrp, ob, true, false, false);
+ }
+ else {
+ DRW_shgroup_call(shgrp, geom, ob);
+ }
+ }
+
+ if (dupli) {
+ dupli->wire_shgrp = shgrp;
+ dupli->wire_geom = geom;
+ }
+ }
+ else if (is_mesh && (!is_edit_mode || has_edit_mesh_cage)) {
+ OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+ Mesh *me = ob->data;
+ float *color;
+ DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+
+ /* Draw loose geometry. */
+ if ((me->totpoly == 0 && me->totedge > 0) || has_edit_mesh_cage) {
+ struct GPUBatch *geom = DRW_cache_mesh_loose_edges_get(ob);
+ if (geom) {
+ OVERLAY_extra_wire(cb, geom, ob->obmat, color);
+ }
+ }
+ else if (me->totedge == 0 && me->totvert > 0) {
+ struct GPUBatch *geom = DRW_cache_mesh_all_verts_get(ob);
+ if (geom) {
+ OVERLAY_extra_loose_points(cb, geom, ob->obmat, color);
+ }
+ }
+ }
+}
+
+void OVERLAY_wireframe_draw(OVERLAY_Data *data)
+{
+ OVERLAY_FramebufferList *fbl = data->fbl;
+ OVERLAY_PassList *psl = data->psl;
+ OVERLAY_PrivateData *pd = data->stl->pd;
+
+ if (pd->antialiasing.enabled) {
+ GPU_framebuffer_bind(fbl->overlay_line_fb);
+ }
+
+ DRW_view_set_active(pd->view_wires);
+ DRW_draw_pass(psl->wireframe_ps);
+
+ DRW_view_set_active(pd->view_default);
+
+ if (pd->antialiasing.enabled) {
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
+}
+
+void OVERLAY_wireframe_in_front_draw(OVERLAY_Data *data)
+{
+ OVERLAY_PassList *psl = data->psl;
+ OVERLAY_PrivateData *pd = data->stl->pd;
+
+ DRW_view_set_active(pd->view_wires);
+ DRW_draw_pass(psl->wireframe_xray_ps);
+
+ DRW_view_set_active(pd->view_default);
+}
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
+}
diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c
index abfa57dd218..f6e54eef4ed 100644
--- a/source/blender/draw/engines/select/select_engine.c
+++ b/source/blender/draw/engines/select/select_engine.c
@@ -147,8 +147,8 @@ static void select_engine_init(void *vedata)
/* Create view with depth offset */
stl->g_data->view_faces = (DRWView *)view_default;
- stl->g_data->view_edges = DRW_view_create_with_zoffset(draw_ctx->rv3d, 1.0f);
- stl->g_data->view_verts = DRW_view_create_with_zoffset(draw_ctx->rv3d, 1.1f);
+ stl->g_data->view_edges = DRW_view_create_with_zoffset(view_default, draw_ctx->rv3d, 1.0f);
+ stl->g_data->view_verts = DRW_view_create_with_zoffset(view_default, draw_ctx->rv3d, 1.1f);
}
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl
index 092878e43aa..95ca2c0c297 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl
@@ -9,8 +9,6 @@ uniform vec2 invertedViewportSize;
void main()
{
ivec2 texel = ivec2(gl_FragCoord.xy);
- float alpha = texelFetch(colorBuffer, texel, 0).a;
FragColor = FxaaPixelShader(
uvcoordsvar.st, colorBuffer, invertedViewportSize, 1.0, 0.166, 0.0833);
- FragColor.a = alpha;
}
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index f84bd34545c..e5872dbac50 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -74,7 +74,6 @@ static struct {
/* TODO(fclem) move everything below to wpd and custom viewlayer data. */
struct GPUTexture *oit_accum_tx; /* ref only, not alloced */
struct GPUTexture *oit_revealage_tx; /* ref only, not alloced */
- struct GPUTexture *ghost_depth_tx; /* ref only, not alloced */
struct GPUTexture *object_id_tx; /* ref only, not alloced */
struct GPUTexture *color_buffer_tx; /* ref only, not alloced */
struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */
@@ -582,7 +581,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
psl->ghost_resolve_pass = DRW_pass_create("Resolve Ghost Depth",
DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
grp = DRW_shgroup_create(e_data.ghost_resolve_sh, psl->ghost_resolve_pass);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.ghost_depth_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth_in_front);
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
@@ -621,23 +620,6 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
}
}
-static void workbench_setup_ghost_framebuffer(WORKBENCH_FramebufferList *fbl)
-{
- const float *viewport_size = DRW_viewport_size_get();
- const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
-
- e_data.ghost_depth_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_DEPTH_COMPONENT24, &draw_engine_workbench_solid);
-
- GPU_framebuffer_ensure_config(&fbl->ghost_prepass_fb,
- {
- GPU_ATTACHMENT_TEXTURE(e_data.ghost_depth_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
- GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx),
- });
-}
-
void workbench_deferred_engine_free(void)
{
for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
@@ -1217,8 +1199,33 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
}
}
-void workbench_deferred_cache_finish(WORKBENCH_Data *UNUSED(vedata))
+void workbench_deferred_cache_finish(WORKBENCH_Data *vedata)
{
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+
+ if (GHOST_ENABLED(psl)) {
+ /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0);
+
+ GPU_framebuffer_ensure_config(
+ &dfbl->default_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+ GPU_framebuffer_ensure_config(
+ &dfbl->in_front_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+
+ GPU_framebuffer_ensure_config(&fbl->ghost_prepass_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
+ GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx),
+ });
+ }
}
void workbench_deferred_draw_background(WORKBENCH_Data *vedata)
@@ -1252,6 +1259,7 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
WORKBENCH_FramebufferList *fbl = vedata->fbl;
WORKBENCH_PrivateData *wpd = stl->g_data;
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
if (workbench_is_taa_enabled(wpd)) {
workbench_taa_draw_scene_start(vedata);
@@ -1262,12 +1270,17 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
DRW_draw_pass(psl->prepass_pass);
DRW_draw_pass(psl->prepass_hair_pass);
- if (GHOST_ENABLED(psl)) {
- /* meh, late init to not request a depth buffer we won't use. */
- workbench_setup_ghost_framebuffer(fbl);
-
+ if (fbl->ghost_prepass_fb) {
GPU_framebuffer_bind(fbl->ghost_prepass_fb);
GPU_framebuffer_clear_depth(fbl->ghost_prepass_fb, 1.0f);
+ }
+ else if (dtxl->depth_in_front) {
+ /* TODO(fclem) This clear should be done in a global place. */
+ GPU_framebuffer_bind(dfbl->in_front_fb);
+ GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f);
+ }
+
+ if (GHOST_ENABLED(psl)) {
DRW_draw_pass(psl->ghost_prepass_pass);
DRW_draw_pass(psl->ghost_prepass_hair_pass);
@@ -1318,6 +1331,7 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
/* In order to not draw on top of ghost objects, we clear the stencil
* to 0xFF and the ghost object to 0x00 and only draw overlays on top if
* stencil is not 0. */
+ /* TODO(fclem) Remove this hack. */
GPU_framebuffer_bind(dfbl->depth_only_fb);
GPU_framebuffer_clear_stencil(dfbl->depth_only_fb, 0xFF);
@@ -1335,7 +1349,6 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
DRW_draw_pass(psl->background_pass);
if (OIT_ENABLED(wpd) && !DRW_pass_is_empty(psl->transparent_accum_pass)) {
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
/* meh, late init to not request buffers we won't use. */
workbench_init_oit_framebuffer(fbl, dtxl);