From 2fffd7d7a85d9e35d4f2b6e0de15504178b26e07 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 19 Sep 2022 14:29:58 +0200 Subject: Move overlay engine to C++ This just makes the minimum changes to make the files compile. --- source/blender/draw/CMakeLists.txt | 52 +- .../draw/engines/overlay/overlay_antialiasing.c | 255 -- .../draw/engines/overlay/overlay_antialiasing.cc | 256 ++ .../draw/engines/overlay/overlay_armature.c | 2635 ------------------- .../draw/engines/overlay/overlay_armature.cc | 2646 ++++++++++++++++++++ .../draw/engines/overlay/overlay_background.c | 114 - .../draw/engines/overlay/overlay_background.cc | 114 + .../draw/engines/overlay/overlay_edit_curve.c | 121 - .../draw/engines/overlay/overlay_edit_curve.cc | 121 + .../draw/engines/overlay/overlay_edit_curves.cc | 2 +- .../draw/engines/overlay/overlay_edit_mesh.c | 381 --- .../draw/engines/overlay/overlay_edit_mesh.cc | 382 +++ .../draw/engines/overlay/overlay_edit_text.c | 219 -- .../draw/engines/overlay/overlay_edit_text.cc | 219 ++ .../blender/draw/engines/overlay/overlay_edit_uv.c | 586 ----- .../draw/engines/overlay/overlay_edit_uv.cc | 596 +++++ .../blender/draw/engines/overlay/overlay_engine.c | 747 ------ .../blender/draw/engines/overlay/overlay_engine.cc | 751 ++++++ .../blender/draw/engines/overlay/overlay_engine.h | 8 + .../blender/draw/engines/overlay/overlay_extra.c | 1621 ------------ .../blender/draw/engines/overlay/overlay_extra.cc | 1623 ++++++++++++ .../blender/draw/engines/overlay/overlay_facing.c | 73 - .../blender/draw/engines/overlay/overlay_facing.cc | 73 + source/blender/draw/engines/overlay/overlay_fade.c | 83 - .../blender/draw/engines/overlay/overlay_fade.cc | 83 + .../blender/draw/engines/overlay/overlay_gpencil.c | 471 ---- .../draw/engines/overlay/overlay_gpencil.cc | 474 ++++ source/blender/draw/engines/overlay/overlay_grid.c | 306 --- .../blender/draw/engines/overlay/overlay_grid.cc | 307 +++ .../blender/draw/engines/overlay/overlay_image.c | 498 ---- .../blender/draw/engines/overlay/overlay_image.cc | 500 ++++ .../blender/draw/engines/overlay/overlay_lattice.c | 68 - .../draw/engines/overlay/overlay_lattice.cc | 68 + .../draw/engines/overlay/overlay_metaball.c | 132 - .../draw/engines/overlay/overlay_metaball.cc | 133 + .../draw/engines/overlay/overlay_mode_transfer.c | 144 -- .../draw/engines/overlay/overlay_mode_transfer.cc | 144 ++ .../draw/engines/overlay/overlay_motion_path.c | 220 -- .../draw/engines/overlay/overlay_motion_path.cc | 220 ++ .../blender/draw/engines/overlay/overlay_outline.c | 379 --- .../draw/engines/overlay/overlay_outline.cc | 378 +++ .../blender/draw/engines/overlay/overlay_paint.c | 274 -- .../blender/draw/engines/overlay/overlay_paint.cc | 275 ++ .../draw/engines/overlay/overlay_particle.c | 207 -- .../draw/engines/overlay/overlay_particle.cc | 207 ++ .../blender/draw/engines/overlay/overlay_private.h | 776 ------ .../draw/engines/overlay/overlay_private.hh | 776 ++++++ .../blender/draw/engines/overlay/overlay_sculpt.c | 77 - .../blender/draw/engines/overlay/overlay_sculpt.cc | 77 + .../draw/engines/overlay/overlay_sculpt_curves.cc | 2 +- .../blender/draw/engines/overlay/overlay_shader.c | 1082 -------- .../blender/draw/engines/overlay/overlay_shader.cc | 1082 ++++++++ .../draw/engines/overlay/overlay_shader_shared.h | 3 + .../blender/draw/engines/overlay/overlay_volume.c | 53 - .../blender/draw/engines/overlay/overlay_volume.cc | 53 + .../draw/engines/overlay/overlay_wireframe.c | 360 --- .../draw/engines/overlay/overlay_wireframe.cc | 362 +++ source/blender/draw/tests/shaders_test.cc | 2 +- 58 files changed, 11960 insertions(+), 11911 deletions(-) delete mode 100644 source/blender/draw/engines/overlay/overlay_antialiasing.c create mode 100644 source/blender/draw/engines/overlay/overlay_antialiasing.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_armature.c create mode 100644 source/blender/draw/engines/overlay/overlay_armature.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_background.c create mode 100644 source/blender/draw/engines/overlay/overlay_background.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_edit_curve.c create mode 100644 source/blender/draw/engines/overlay/overlay_edit_curve.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_edit_mesh.c create mode 100644 source/blender/draw/engines/overlay/overlay_edit_mesh.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_edit_text.c create mode 100644 source/blender/draw/engines/overlay/overlay_edit_text.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_edit_uv.c create mode 100644 source/blender/draw/engines/overlay/overlay_edit_uv.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_engine.c create mode 100644 source/blender/draw/engines/overlay/overlay_engine.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_extra.c create mode 100644 source/blender/draw/engines/overlay/overlay_extra.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_facing.c create mode 100644 source/blender/draw/engines/overlay/overlay_facing.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_fade.c create mode 100644 source/blender/draw/engines/overlay/overlay_fade.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_gpencil.c create mode 100644 source/blender/draw/engines/overlay/overlay_gpencil.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_grid.c create mode 100644 source/blender/draw/engines/overlay/overlay_grid.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_image.c create mode 100644 source/blender/draw/engines/overlay/overlay_image.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_lattice.c create mode 100644 source/blender/draw/engines/overlay/overlay_lattice.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_metaball.c create mode 100644 source/blender/draw/engines/overlay/overlay_metaball.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_mode_transfer.c create mode 100644 source/blender/draw/engines/overlay/overlay_mode_transfer.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_motion_path.c create mode 100644 source/blender/draw/engines/overlay/overlay_motion_path.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_outline.c create mode 100644 source/blender/draw/engines/overlay/overlay_outline.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_paint.c create mode 100644 source/blender/draw/engines/overlay/overlay_paint.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_particle.c create mode 100644 source/blender/draw/engines/overlay/overlay_particle.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_private.h create mode 100644 source/blender/draw/engines/overlay/overlay_private.hh delete mode 100644 source/blender/draw/engines/overlay/overlay_sculpt.c create mode 100644 source/blender/draw/engines/overlay/overlay_sculpt.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_shader.c create mode 100644 source/blender/draw/engines/overlay/overlay_shader.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_volume.c create mode 100644 source/blender/draw/engines/overlay/overlay_volume.cc delete mode 100644 source/blender/draw/engines/overlay/overlay_wireframe.c create mode 100644 source/blender/draw/engines/overlay/overlay_wireframe.cc diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 32103692421..8b61d8686cd 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -176,33 +176,33 @@ set(SRC engines/gpencil/gpencil_shader_fx.c engines/select/select_draw_utils.c engines/select/select_engine.c - engines/overlay/overlay_antialiasing.c - engines/overlay/overlay_armature.c - engines/overlay/overlay_background.c - engines/overlay/overlay_edit_curve.c + engines/overlay/overlay_antialiasing.cc + engines/overlay/overlay_armature.cc + engines/overlay/overlay_background.cc + engines/overlay/overlay_edit_curve.cc engines/overlay/overlay_edit_curves.cc - engines/overlay/overlay_edit_mesh.c - engines/overlay/overlay_edit_text.c - engines/overlay/overlay_edit_uv.c - engines/overlay/overlay_engine.c - engines/overlay/overlay_extra.c - engines/overlay/overlay_facing.c - engines/overlay/overlay_fade.c - engines/overlay/overlay_gpencil.c - engines/overlay/overlay_grid.c - engines/overlay/overlay_image.c - engines/overlay/overlay_lattice.c - engines/overlay/overlay_metaball.c - engines/overlay/overlay_mode_transfer.c - engines/overlay/overlay_motion_path.c - engines/overlay/overlay_outline.c - engines/overlay/overlay_paint.c - engines/overlay/overlay_particle.c - engines/overlay/overlay_sculpt.c + engines/overlay/overlay_edit_mesh.cc + engines/overlay/overlay_edit_text.cc + engines/overlay/overlay_edit_uv.cc + engines/overlay/overlay_engine.cc + engines/overlay/overlay_extra.cc + engines/overlay/overlay_facing.cc + engines/overlay/overlay_fade.cc + engines/overlay/overlay_gpencil.cc + engines/overlay/overlay_grid.cc + engines/overlay/overlay_image.cc + engines/overlay/overlay_lattice.cc + engines/overlay/overlay_metaball.cc + engines/overlay/overlay_mode_transfer.cc + engines/overlay/overlay_motion_path.cc + engines/overlay/overlay_outline.cc + engines/overlay/overlay_paint.cc + engines/overlay/overlay_particle.cc + engines/overlay/overlay_sculpt.cc engines/overlay/overlay_sculpt_curves.cc - engines/overlay/overlay_shader.c - engines/overlay/overlay_volume.c - engines/overlay/overlay_wireframe.c + engines/overlay/overlay_shader.cc + engines/overlay/overlay_volume.cc + engines/overlay/overlay_wireframe.cc DRW_engine.h DRW_select_buffer.h @@ -286,7 +286,7 @@ set(SRC engines/select/select_engine.h engines/select/select_private.h engines/overlay/overlay_engine.h - engines/overlay/overlay_private.h + engines/overlay/overlay_private.hh ) set(LIB diff --git a/source/blender/draw/engines/overlay/overlay_antialiasing.c b/source/blender/draw/engines/overlay/overlay_antialiasing.c deleted file mode 100644 index 5bdc1096edc..00000000000 --- a/source/blender/draw/engines/overlay/overlay_antialiasing.c +++ /dev/null @@ -1,255 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * 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 - * overlapping / 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 flickering 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 screen-space. - * - Only uses one additional lightweight full-screen 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_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(); - - /* Small texture which will have very small impact on render-time. */ - if (txl->dummy_depth_tx == NULL) { - const float pixel[1] = {1.0f}; - txl->dummy_depth_tx = DRW_texture_create_2d(1, 1, GPU_DEPTH_COMPONENT24, 0, pixel); - } - - if (!DRW_state_is_fbo()) { - pd->antialiasing.enabled = false; - return; - } - - bool need_wire_expansion = (G_draw.block.size_pixel > 1.0f); - pd->antialiasing.enabled = need_wire_expansion || - ((U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) != 0); - - GPUTexture *color_tex = NULL; - GPUTexture *line_tex = NULL; - - if (pd->antialiasing.enabled) { - DRW_texture_ensure_fullscreen_2d(&txl->overlay_color_tx, GPU_SRGB8_A8, DRW_TEX_FILTER); - DRW_texture_ensure_fullscreen_2d(&txl->overlay_line_tx, GPU_RGBA8, 0); - - color_tex = txl->overlay_color_tx; - line_tex = txl->overlay_line_tx; - } - else { - /* Just a copy of the defaults frame-buffers. */ - color_tex = dtxl->color_overlay; - } - - GPU_framebuffer_ensure_config(&fbl->overlay_color_only_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(color_tex), - }); - GPU_framebuffer_ensure_config(&fbl->overlay_default_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(color_tex), - }); - GPU_framebuffer_ensure_config(&fbl->overlay_line_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(color_tex), - GPU_ATTACHMENT_TEXTURE(line_tex), - }); -} - -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) { - /* `antialiasing.enabled` is also enabled for wire expansion. Check here if - * anti aliasing is needed. */ - const bool do_smooth_lines = (U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) != 0; - - 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_bool_copy(grp, "doSmoothLines", do_smooth_lines); - 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); - } - - /* A bit out of place... not related to antialiasing. */ - if (pd->xray_enabled) { - DRW_PASS_CREATE(psl->xray_fade_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL); - - sh = OVERLAY_shader_xray_fade(); - grp = DRW_shgroup_create(sh, psl->xray_fade_ps); - DRW_shgroup_uniform_texture_ref(grp, "depthTex", &dtxl->depth); - DRW_shgroup_uniform_texture_ref(grp, "xrayDepthTex", &txl->temp_depth_tx); - DRW_shgroup_uniform_float_copy(grp, "opacity", 1.0f - pd->xray_opacity); - 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_PassList *psl = vedata->psl; - 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)}); - - GPU_framebuffer_ensure_config(&fbl->overlay_line_in_front_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), - GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx), - GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)}); - } - else { - GPU_framebuffer_ensure_config(&fbl->overlay_in_front_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), - GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay)}); - - GPU_framebuffer_ensure_config(&fbl->overlay_line_in_front_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), - GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), - GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)}); - } - - pd->antialiasing.do_depth_copy = !(psl->wireframe_ps == NULL || - DRW_pass_is_empty(psl->wireframe_ps)) || - (pd->xray_enabled && pd->xray_opacity > 0.0f); - pd->antialiasing.do_depth_infront_copy = !(psl->wireframe_xray_ps == NULL || - DRW_pass_is_empty(psl->wireframe_xray_ps)); - - const bool do_wireframe = pd->antialiasing.do_depth_copy || - pd->antialiasing.do_depth_infront_copy; - if (pd->xray_enabled || do_wireframe) { - DRW_texture_ensure_fullscreen_2d(&txl->temp_depth_tx, GPU_DEPTH24_STENCIL8, 0); - } -} - -void OVERLAY_antialiasing_start(OVERLAY_Data *vedata) -{ - OVERLAY_FramebufferList *fbl = vedata->fbl; - OVERLAY_PrivateData *pd = vedata->stl->pd; - - if (pd->antialiasing.enabled) { - const 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); - } - - /* If we are not in solid shading mode, we clear the depth. */ - if (DRW_state_is_fbo() && pd->clear_in_front) { - /* TODO(fclem): This clear should be done in a global place. */ - GPU_framebuffer_bind(fbl->overlay_in_front_fb); - GPU_framebuffer_clear_depth(fbl->overlay_in_front_fb, 1.0f); - } -} - -void OVERLAY_xray_depth_copy(OVERLAY_Data *vedata) -{ - OVERLAY_FramebufferList *fbl = vedata->fbl; - OVERLAY_TextureList *txl = vedata->txl; - OVERLAY_PrivateData *pd = vedata->stl->pd; - - if (DRW_state_is_fbo() && pd->antialiasing.do_depth_copy) { - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - /* We copy the depth of the rendered geometry to be able to compare to the overlays depth. */ - GPU_texture_copy(txl->temp_depth_tx, dtxl->depth); - } - - if (DRW_state_is_fbo() && pd->xray_enabled) { - /* We then clear to not occlude the overlays directly. */ - GPU_framebuffer_bind(fbl->overlay_default_fb); - GPU_framebuffer_clear_depth(fbl->overlay_default_fb, 1.0f); - } -} - -void OVERLAY_xray_depth_infront_copy(OVERLAY_Data *vedata) -{ - OVERLAY_TextureList *txl = vedata->txl; - OVERLAY_PrivateData *pd = vedata->stl->pd; - - if (DRW_state_is_fbo() && pd->antialiasing.do_depth_infront_copy) { - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - /* We copy the depth of the rendered geometry to be able to compare to the overlays depth. */ - GPU_texture_copy(txl->temp_depth_tx, dtxl->depth_in_front); - } -} - -void OVERLAY_xray_fade_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_PrivateData *pd = vedata->stl->pd; - - if (DRW_state_is_fbo() && pd->xray_enabled && pd->xray_opacity > 0.0f) { - /* Partially occlude overlays using the geometry depth pass. */ - DRW_draw_pass(psl->xray_fade_ps); - } -} - -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->overlay_only_fb); - DRW_draw_pass(psl->antialiasing_ps); - } -} diff --git a/source/blender/draw/engines/overlay/overlay_antialiasing.cc b/source/blender/draw/engines/overlay/overlay_antialiasing.cc new file mode 100644 index 00000000000..2242ad8b609 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_antialiasing.cc @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * 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 + * overlapping / 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 flickering 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 screen-space. + * - Only uses one additional lightweight full-screen buffer (compared to MSAA/SMAA). + * - No convergence time (compared to TAA). + */ + +#include "DRW_render.h" + +#include "ED_screen.h" + +#include "overlay_private.hh" + +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(); + + /* Small texture which will have very small impact on render-time. */ + if (txl->dummy_depth_tx == NULL) { + const float pixel[1] = {1.0f}; + txl->dummy_depth_tx = DRW_texture_create_2d( + 1, 1, GPU_DEPTH_COMPONENT24, DRWTextureFlag(0), pixel); + } + + if (!DRW_state_is_fbo()) { + pd->antialiasing.enabled = false; + return; + } + + bool need_wire_expansion = (G_draw.block.size_pixel > 1.0f); + pd->antialiasing.enabled = need_wire_expansion || + ((U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) != 0); + + GPUTexture *color_tex = NULL; + GPUTexture *line_tex = NULL; + + if (pd->antialiasing.enabled) { + DRW_texture_ensure_fullscreen_2d(&txl->overlay_color_tx, GPU_SRGB8_A8, DRW_TEX_FILTER); + DRW_texture_ensure_fullscreen_2d(&txl->overlay_line_tx, GPU_RGBA8, DRWTextureFlag(0)); + + color_tex = txl->overlay_color_tx; + line_tex = txl->overlay_line_tx; + } + else { + /* Just a copy of the defaults frame-buffers. */ + color_tex = dtxl->color_overlay; + } + + GPU_framebuffer_ensure_config(&fbl->overlay_color_only_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(color_tex), + }); + GPU_framebuffer_ensure_config(&fbl->overlay_default_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(color_tex), + }); + GPU_framebuffer_ensure_config(&fbl->overlay_line_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(color_tex), + GPU_ATTACHMENT_TEXTURE(line_tex), + }); +} + +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) { + /* `antialiasing.enabled` is also enabled for wire expansion. Check here if + * anti aliasing is needed. */ + const bool do_smooth_lines = (U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) != 0; + + 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_bool_copy(grp, "doSmoothLines", do_smooth_lines); + 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); + } + + /* A bit out of place... not related to antialiasing. */ + if (pd->xray_enabled) { + DRW_PASS_CREATE(psl->xray_fade_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL); + + sh = OVERLAY_shader_xray_fade(); + grp = DRW_shgroup_create(sh, psl->xray_fade_ps); + DRW_shgroup_uniform_texture_ref(grp, "depthTex", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "xrayDepthTex", &txl->temp_depth_tx); + DRW_shgroup_uniform_float_copy(grp, "opacity", 1.0f - pd->xray_opacity); + 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_PassList *psl = vedata->psl; + 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)}); + + GPU_framebuffer_ensure_config(&fbl->overlay_line_in_front_fb, + {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), + GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx), + GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)}); + } + else { + GPU_framebuffer_ensure_config(&fbl->overlay_in_front_fb, + {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), + GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay)}); + + GPU_framebuffer_ensure_config(&fbl->overlay_line_in_front_fb, + {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), + GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), + GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)}); + } + + pd->antialiasing.do_depth_copy = !(psl->wireframe_ps == NULL || + DRW_pass_is_empty(psl->wireframe_ps)) || + (pd->xray_enabled && pd->xray_opacity > 0.0f); + pd->antialiasing.do_depth_infront_copy = !(psl->wireframe_xray_ps == NULL || + DRW_pass_is_empty(psl->wireframe_xray_ps)); + + const bool do_wireframe = pd->antialiasing.do_depth_copy || + pd->antialiasing.do_depth_infront_copy; + if (pd->xray_enabled || do_wireframe) { + DRW_texture_ensure_fullscreen_2d(&txl->temp_depth_tx, GPU_DEPTH24_STENCIL8, DRWTextureFlag(0)); + } +} + +void OVERLAY_antialiasing_start(OVERLAY_Data *vedata) +{ + OVERLAY_FramebufferList *fbl = vedata->fbl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + + if (pd->antialiasing.enabled) { + const 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); + } + + /* If we are not in solid shading mode, we clear the depth. */ + if (DRW_state_is_fbo() && pd->clear_in_front) { + /* TODO(fclem): This clear should be done in a global place. */ + GPU_framebuffer_bind(fbl->overlay_in_front_fb); + GPU_framebuffer_clear_depth(fbl->overlay_in_front_fb, 1.0f); + } +} + +void OVERLAY_xray_depth_copy(OVERLAY_Data *vedata) +{ + OVERLAY_FramebufferList *fbl = vedata->fbl; + OVERLAY_TextureList *txl = vedata->txl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + + if (DRW_state_is_fbo() && pd->antialiasing.do_depth_copy) { + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + /* We copy the depth of the rendered geometry to be able to compare to the overlays depth. */ + GPU_texture_copy(txl->temp_depth_tx, dtxl->depth); + } + + if (DRW_state_is_fbo() && pd->xray_enabled) { + /* We then clear to not occlude the overlays directly. */ + GPU_framebuffer_bind(fbl->overlay_default_fb); + GPU_framebuffer_clear_depth(fbl->overlay_default_fb, 1.0f); + } +} + +void OVERLAY_xray_depth_infront_copy(OVERLAY_Data *vedata) +{ + OVERLAY_TextureList *txl = vedata->txl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + + if (DRW_state_is_fbo() && pd->antialiasing.do_depth_infront_copy) { + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + /* We copy the depth of the rendered geometry to be able to compare to the overlays depth. */ + GPU_texture_copy(txl->temp_depth_tx, dtxl->depth_in_front); + } +} + +void OVERLAY_xray_fade_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + + if (DRW_state_is_fbo() && pd->xray_enabled && pd->xray_opacity > 0.0f) { + /* Partially occlude overlays using the geometry depth pass. */ + DRW_draw_pass(psl->xray_fade_ps); + } +} + +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->overlay_only_fb); + DRW_draw_pass(psl->antialiasing_ps); + } +} diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c deleted file mode 100644 index df5ee6a18c0..00000000000 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ /dev/null @@ -1,2635 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include -#include -#include - -#include "DNA_armature_types.h" -#include "DNA_constraint_types.h" -#include "DNA_mesh_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_view3d_types.h" - -#include "DRW_render.h" - -#include "BLI_math.h" -#include "BLI_utildefines.h" - -#include "BKE_action.h" -#include "BKE_armature.h" -#include "BKE_deform.h" -#include "BKE_modifier.h" -#include "BKE_object.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" - -#include "draw_cache_impl.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; - - /* 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; - -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_ALL_WEIGHT_PAINT)) { - 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(); - const bool is_select_mode = DRW_state_is_select(); - 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) && - !is_select_mode; - pd->armature.do_pose_xray = (pd->overlay.flag & V3D_OVERLAY_BONE_SELECT) != 0; - pd->armature.do_pose_fade_geom = pd->armature.do_pose_xray && - ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) == 0) && - draw_ctx->object_pose != NULL; - - const float wire_alpha = pd->overlay.bone_wire_alpha; - const bool use_wire_alpha = (wire_alpha < 1.0f); - - DRWState 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]; - - cb->solid.custom_shapes_ghash = BLI_ghash_ptr_new(__func__); - cb->transp.custom_shapes_ghash = BLI_ghash_ptr_new(__func__); - - DRWPass **p_armature_ps = &psl->armature_ps[i]; - 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_WRITE_DEPTH; - DRW_PASS_CREATE(*p_armature_ps, state | pd->clipping_state | infront_state); - DRWPass *armature_ps = *p_armature_ps; - - DRWPass **p_armature_trans_ps = &psl->armature_transp_ps[i]; - state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ADD; - DRW_PASS_CREATE(*p_armature_trans_ps, state | pd->clipping_state); - DRWPass *armature_transp_ps = *p_armature_trans_ps; - -#define BUF_INSTANCE DRW_shgroup_call_buffer_instance -#define BUF_LINE(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_LINES) -#define BUF_POINT(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_POINTS) - - { - format = formats->instance_bone; - - sh = OVERLAY_shader_armature_sphere(false); - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); - cb->solid.point_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get()); - - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH); - DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); - DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.4f); - cb->transp.point_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get()); - - sh = OVERLAY_shader_armature_shape(false); - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); - cb->solid.custom_fill = grp; - cb->solid.box_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get()); - cb->solid.octa_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get()); - - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH); - DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); - DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.6f); - cb->transp.custom_fill = grp; - cb->transp.box_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get()); - cb->transp.octa_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get()); - - sh = OVERLAY_shader_armature_sphere(true); - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); - cb->solid.point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get()); - - if (use_wire_alpha) { - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); - cb->transp.point_outline = BUF_INSTANCE( - grp, format, DRW_cache_bone_point_wire_outline_get()); - } - else { - cb->transp.point_outline = cb->solid.point_outline; - } - - sh = OVERLAY_shader_armature_shape(true); - cb->solid.custom_outline = grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); - cb->solid.box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get()); - cb->solid.octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get()); - - if (use_wire_alpha) { - cb->transp.custom_outline = grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); - cb->transp.box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get()); - cb->transp.octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get()); - } - else { - cb->transp.custom_outline = cb->solid.custom_outline; - cb->transp.box_outline = cb->solid.box_outline; - cb->transp.octa_outline = cb->solid.octa_outline; - } - - sh = OVERLAY_shader_armature_shape_wire(); - cb->solid.custom_wire = grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); - - if (use_wire_alpha) { - cb->transp.custom_wire = grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); - } - else { - cb->transp.custom_wire = cb->solid.custom_wire; - } - } - { - format = formats->instance_extra; - - sh = OVERLAY_shader_armature_degrees_of_freedom_wire(); - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); - cb->solid.dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get()); - - if (use_wire_alpha) { - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); - cb->transp.dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get()); - } - else { - cb->transp.dof_lines = cb->solid.dof_lines; - } - - sh = OVERLAY_shader_armature_degrees_of_freedom_solid(); - grp = DRW_shgroup_create(sh, armature_transp_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); - cb->solid.dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get()); - - if (use_wire_alpha) { - grp = DRW_shgroup_create(sh, armature_transp_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); - cb->transp.dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get()); - } - else { - cb->transp.dof_sphere = cb->solid.dof_sphere; - } - } - { - format = formats->instance_bone_stick; - - sh = OVERLAY_shader_armature_stick(); - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); - cb->solid.stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get()); - - if (use_wire_alpha) { - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); - cb->transp.stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get()); - } - else { - cb->transp.stick = cb->solid.stick; - } - } - { - format = formats->instance_bone_envelope; - - sh = OVERLAY_shader_armature_envelope(false); - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_state_enable(grp, DRW_STATE_CULL_BACK); - DRW_shgroup_uniform_bool_copy(grp, "isDistance", false); - DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); - cb->solid.envelope_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get()); - - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH); - DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA | DRW_STATE_CULL_BACK); - DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.6f); - cb->transp.envelope_fill = 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_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); - cb->solid.envelope_outline = BUF_INSTANCE( - grp, format, DRW_cache_bone_envelope_outline_get()); - - if (use_wire_alpha) { - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); - cb->transp.envelope_outline = BUF_INSTANCE( - grp, format, DRW_cache_bone_envelope_outline_get()); - } - else { - cb->transp.envelope_outline = cb->solid.envelope_outline; - } - - format = formats->instance_bone_envelope_distance; - - sh = OVERLAY_shader_armature_envelope(false); - grp = DRW_shgroup_create(sh, armature_transp_ps); - DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); - DRW_shgroup_uniform_bool_copy(grp, "isDistance", true); - DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT); - cb->solid.envelope_distance = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get()); - - if (use_wire_alpha) { - grp = DRW_shgroup_create(sh, armature_transp_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); - DRW_shgroup_uniform_bool_copy(grp, "isDistance", true); - DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT); - cb->transp.envelope_distance = BUF_INSTANCE( - grp, format, DRW_cache_bone_envelope_solid_get()); - } - else { - cb->transp.envelope_distance = cb->solid.envelope_distance; - } - } - { - format = formats->pos_color; - - sh = OVERLAY_shader_armature_wire(); - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); - cb->solid.wire = BUF_LINE(grp, format); - - if (use_wire_alpha) { - grp = DRW_shgroup_create(sh, armature_ps); - DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); - cb->transp.wire = BUF_LINE(grp, format); - } - else { - cb->transp.wire = cb->solid.wire; - } - } - } -} - -/* -------------------------------------------------------------------- */ -/** \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); - float obscale = mat4_to_scale(ctx->ob->obmat); - head_sph[3] = *radius_head * obscale; - head_sph[3] += *distance * obscale; - tail_sph[3] = *radius_tail * obscale; - tail_sph[3] += *distance * obscale; - 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); - float obscale = mat4_to_scale(ctx->ob->obmat); - head_sph[3] = *radius_head * obscale; - tail_sph[3] = *radius_tail * obscale; - - 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_delayed(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_mesh(ArmatureDrawContext *ctx, - Mesh *mesh, - 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_mesh_batch_cache_validate(custom, mesh); - - struct GPUBatch *surf = DRW_mesh_batch_cache_get_surface(mesh); - struct GPUBatch *edges = DRW_mesh_batch_cache_get_edge_detection(mesh, NULL); - struct GPUBatch *ledges = DRW_mesh_batch_cache_get_loose_edges(mesh); - 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_delayed(custom); -} - -static void drw_shgroup_bone_custom_mesh_wire(ArmatureDrawContext *ctx, - Mesh *mesh, - 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_mesh_batch_cache_validate(custom, mesh); - - struct GPUBatch *geom = DRW_mesh_batch_cache_get_all_edges(mesh); - 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_delayed(custom); -} - -static void drw_shgroup_custom_bone_curve(ArmatureDrawContext *ctx, - Curve *curve, - const float (*bone_mat)[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_curve_batch_cache_validate(curve); - - /* This only handles curves without any surface. The other curve types should have been converted - * to meshes and rendered in the mesh drawing function. */ - struct GPUBatch *ledges = NULL; - if (custom->type == OB_FONT) { - ledges = DRW_cache_text_edge_wire_get(custom); - } - else { - ledges = DRW_cache_curve_edge_wire_get(custom); - } - - if (ledges) { - BoneInstanceData inst_data; - mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); - - DRWCallBuffer *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_delayed(custom); -} - -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) -{ - /* The custom object is not an evaluated object, so its object->data field hasn't been replaced - * by #data_eval. This is bad since it gives preference to an object's evaluated mesh over any - * other data type, but supporting all evaluated geometry components would require a much - * larger refactor of this area. */ - Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(custom); - if (mesh != NULL) { - drw_shgroup_bone_custom_solid_mesh( - ctx, mesh, bone_mat, bone_color, hint_color, outline_color, custom); - return; - } - - if (ELEM(custom->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) { - drw_shgroup_custom_bone_curve(ctx, custom->data, bone_mat, outline_color, custom); - } -} - -static void drw_shgroup_bone_custom_wire(ArmatureDrawContext *ctx, - const float (*bone_mat)[4], - const float color[4], - Object *custom) -{ - /* See comments in #drw_shgroup_bone_custom_solid. */ - Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(custom); - if (mesh != NULL) { - drw_shgroup_bone_custom_mesh_wire(ctx, mesh, bone_mat, color, custom); - return; - } - - if (ELEM(custom->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) { - drw_shgroup_custom_bone_curve(ctx, custom->data, bone_mat, color, custom); - } -} - -static void drw_shgroup_bone_custom_empty(ArmatureDrawContext *ctx, - const float (*bone_mat)[4], - const float color[4], - Object *custom) -{ - const 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, G_draw.block.color_wire); -} - -static void drw_shgroup_bone_ik_lines(ArmatureDrawContext *ctx, - const float start[3], - const float end[3]) -{ - drw_shgroup_bone_relationship_lines_ex(ctx, start, end, G_draw.block.color_bone_ik_line); -} - -static void drw_shgroup_bone_ik_no_target_lines(ArmatureDrawContext *ctx, - const float start[3], - const float end[3]) -{ - drw_shgroup_bone_relationship_lines_ex( - ctx, start, end, G_draw.block.color_bone_ik_line_no_target); -} - -static void drw_shgroup_bone_ik_spline_lines(ArmatureDrawContext *ctx, - const float start[3], - const float end[3]) -{ - drw_shgroup_bone_relationship_lines_ex(ctx, start, end, G_draw.block.color_bone_ik_line_spline); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \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) */ -}; - -/* 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 its 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; -} - -/* 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); - /* Meh, hardcoded srgb transform here. */ - srgb_to_linearrgb_v4(fcolor, fcolor); - } - else { - if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) { - copy_v4_v4(fcolor, G_draw.block.color_bone_pose_active); - } - else if (boneflag & BONE_DRAW_ACTIVE) { - copy_v4_v4(fcolor, G_draw.block.color_bone_pose_active_unsel); - } - else if (boneflag & BONE_SELECTED) { - copy_v4_v4(fcolor, G_draw.block.color_bone_pose); - } - else { - copy_v4_v4(fcolor, G_draw.block.color_wire); - } - } - return true; - } - case PCHAN_COLOR_SOLID: { - if (bcolor) { - rgb_uchar_to_float(fcolor, (uchar *)bcolor->solid); - fcolor[3] = 1.0f; - /* Meh, hardcoded srgb transform here. */ - srgb_to_linearrgb_v4(fcolor, fcolor); - } - else { - copy_v4_v4(fcolor, G_draw.block.color_bone_solid); - } - return true; - } - case PCHAN_COLOR_CONSTS: { - if ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS)) { - if (constflag & PCHAN_HAS_TARGET) { - copy_v4_v4(fcolor, G_draw.block.color_bone_pose_target); - } - else if (constflag & PCHAN_HAS_IK) { - copy_v4_v4(fcolor, G_draw.block.color_bone_pose_ik); - } - else if (constflag & PCHAN_HAS_SPLINEIK) { - copy_v4_v4(fcolor, G_draw.block.color_bone_pose_spline_ik); - } - else if (constflag & PCHAN_HAS_CONST) { - copy_v4_v4(fcolor, G_draw.block.color_bone_pose_constraint); - } - else { - return false; - } - return true; - } - return false; - } - } - - return false; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Drawing Color Helpers - * \{ */ - -static void bone_locked_color_shade(float color[4]) -{ - float *locked_color = G_draw.block.color_bone_locked; - - interp_v3_v3v3(color, color, locked_color, locked_color[3]); -} - -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 G_draw.block.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); - - if (boneflag & BONE_DRAW_LOCKED_WEIGHT) { - bone_locked_color_shade(disp_color); - } - - return disp_color; - } - - return G_draw.block.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 G_draw.block.color_bone_solid; - } - - const float *col = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag); - - static float consts_color[4]; - if ((arm->flag & ARM_POSEMODE) && !(boneflag & BONE_DRAW_LOCKED_WEIGHT) && - 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; - } - if (boneflag & (BONE_DRAW_ACTIVE | BONE_SELECTED)) { - return 2.0f; - } - - 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, G_draw.block.color_bone_active); - } - else { - copy_v3_v3(disp_color, G_draw.block.color_bone_select); - } - } - else { - if (boneflag & BONE_DRAW_ACTIVE) { - copy_v3_v3(disp_color, G_draw.block.color_bone_active_unsel); - } - else { - copy_v3_v3(disp_color, G_draw.block.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); - - if (boneflag & BONE_DRAW_LOCKED_WEIGHT) { - bone_locked_color_shade(disp_color); - } - } - else { - copy_v3_v3(disp_color, G_draw.block.color_vertex); - } - - disp_color[3] = get_bone_wire_thickness(ctx, boneflag); - - return disp_color; -} - -static void bone_hint_color_shade(float hint_color[4], const float color[4]) -{ - /* Increase contrast. */ - mul_v3_v3v3(hint_color, color, color); - /* Decrease value to add mode shading to the shape. */ - mul_v3_fl(hint_color, 0.1f); - 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, G_draw.block.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 ebmat[4][4]; - float bone_scale[3]; - 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) { - bone_mat = pchan->pose_mat; - disp_mat = pchan->disp_mat; - disp_tail_mat = pchan->disp_tail_mat; - copy_v3_fl(bone_scale, pchan->bone->length); - } - else { - eBone->length = len_v3v3(eBone->tail, eBone->head); - ED_armature_ebone_to_mat4(eBone, ebmat); - - copy_v3_fl(bone_scale, eBone->length); - bone_mat = ebmat; - disp_mat = eBone->disp_mat; - disp_tail_mat = eBone->disp_tail_mat; - } - - copy_m4_m4(disp_mat, bone_mat); - rescale_m4(disp_mat, bone_scale); - 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, const float result_array[MAX_BBONE_SUBDIV][4][4]) -{ - BBoneSplineParameters param; - EditBone *prev, *next; - float imat[4][4], bonemat[4][4]; - float tmp[3]; - - memset(¶m, 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->bbone_flag & BBONE_ADD_PARENT_END_ROLL)) { - param.roll1 += prev->roll2; - } - - copy_v3_v3(param.scale_in, ebone->scale_in); - copy_v3_v3(param.scale_out, ebone->scale_out); - - param.curve_in_x = ebone->curve_in_x; - param.curve_in_z = ebone->curve_in_z; - - param.curve_out_x = ebone->curve_out_x; - param.curve_out_z = ebone->curve_out_z; - - if (ebone->bbone_flag & BBONE_SCALE_EASING) { - param.ease1 *= param.scale_in[1]; - param.curve_in_x *= param.scale_in[1]; - param.curve_in_z *= param.scale_in[1]; - - param.ease2 *= param.scale_out[1]; - param.curve_out_x *= param.scale_out[1]; - param.curve_out_z *= param.scale_out[1]; - } - - ebone->segments = BKE_pchan_bbone_spline_compute(¶m, 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 bone_scale[3]; - float(*bone_mat)[4]; - float(*disp_mat)[4]; - float(*disp_tail_mat)[4]; - float rot_mat[3][3]; - - /* See TODO: above. */ - mul_v3_v3fl(bone_scale, pchan->custom_scale_xyz, PCHAN_CUSTOM_BONE_LENGTH(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; - - eulO_to_mat3(rot_mat, pchan->custom_rotation_euler, ROT_MODE_XYZ); - - copy_m4_m4(disp_mat, bone_mat); - translate_m4(disp_mat, - pchan->custom_translation[0], - pchan->custom_translation[1], - pchan->custom_translation[2]); - mul_m4_m4m3(disp_mat, disp_mat, rot_mat); - rescale_m4(disp_mat, bone_scale); - 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, - const EditBone *eBone, - const bPoseChannel *pchan, - const bArmature *arm) -{ - float final_col[4]; - const float *col = (ctx->const_color) ? ctx->const_color : - (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? G_draw.block.color_text_hi : - G_draw.block.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.1 : 0.65; - - if (pchan && pchan->custom && !(arm->flag & ARM_NO_CUSTOM)) { - /* Special case: Custom bones can have different scale than the bone. - * Recompute display matrix without the custom scaling applied. (T65640). */ - float axis_mat[4][4]; - float length = pchan->bone->length; - copy_m4_m4(axis_mat, pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat); - rescale_m4(axis_mat, (float[3]){length, length, length}); - translate_m4(axis_mat, 0.0, arm->axes_position - 1.0, 0.0); - - drw_shgroup_bone_axes(ctx, axis_mat, final_col); - } - else { - float disp_mat[4][4]; - copy_m4_m4(disp_mat, BONE_VAR(eBone, pchan, disp_mat)); - translate_m4(disp_mat, 0.0, arm->axes_position - 1.0, 0.0); - drw_shgroup_bone_axes(ctx, 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, G_draw.block.color_bone_solid); - copy_v4_v4(col_solid_tail, G_draw.block.color_bone_solid); - copy_v4_v4(col_wire_root, (ctx->const_color) ? ctx->const_color : G_draw.block.color_vertex); - copy_v4_v4(col_wire_tail, (ctx->const_color) ? ctx->const_color : G_draw.block.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, G_draw.block.color_vertex_select); - } - if (eBone->flag & BONE_TIPSEL) { - copy_v3_v3(col_wire_tail, G_draw.block.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 && (boneflag & BONE_CONNECTED)) : - (pchan->bone->parent && (boneflag & 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 && (boneflag & BONE_DRAW_LOCKED_WEIGHT) == 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 = G_draw.block.color_vertex_select; - } - if (boneflag & BONE_SELECTED) { - col_bone = G_draw.block.color_bone_active; - } - col_wire = G_draw.block.color_wire; - } - - /* Draw root point if we are not connected to our parent. */ - if (!(eBone ? (eBone->parent && (boneflag & BONE_CONNECTED)) : - (pchan->bone->parent && (boneflag & BONE_CONNECTED)))) { - - if (eBone) { - col_head = (eBone->flag & BONE_ROOTSEL) ? G_draw.block.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 rest-space. */ - 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)); - - /* Color Management: Exception here as texts are drawn in sRGB space directly. */ - 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 Pose Bone Culling - * - * Used for selection since drawing many bones can be slow, see: T91253. - * - * Bounding spheres are used with margins added to ensure bones are included. - * An added margin is needed because #BKE_pchan_minmax only returns the bounds - * of the bones head & tail which doesn't account for parts of the bone users may select - * (octahedral spheres or envelope radius for example). - * \{ */ - -static void pchan_culling_calc_bsphere(const Object *ob, - const bPoseChannel *pchan, - BoundSphere *r_bsphere) -{ - float min[3], max[3]; - INIT_MINMAX(min, max); - BKE_pchan_minmax(ob, pchan, true, min, max); - mid_v3_v3v3(r_bsphere->center, min, max); - r_bsphere->radius = len_v3v3(min, r_bsphere->center); -} - -/** - * \return true when bounding sphere from `pchan` intersect the view. - * (same for other "test" functions defined here). - */ -static bool pchan_culling_test_simple(const DRWView *view, - const Object *ob, - const bPoseChannel *pchan) -{ - BoundSphere bsphere; - pchan_culling_calc_bsphere(ob, pchan, &bsphere); - return DRW_culling_sphere_test(view, &bsphere); -} - -static bool pchan_culling_test_with_radius_scale(const DRWView *view, - const Object *ob, - const bPoseChannel *pchan, - const float scale) -{ - BoundSphere bsphere; - pchan_culling_calc_bsphere(ob, pchan, &bsphere); - bsphere.radius *= scale; - return DRW_culling_sphere_test(view, &bsphere); -} - -static bool pchan_culling_test_custom(const DRWView *view, - const Object *ob, - const bPoseChannel *pchan) -{ - /* For more aggressive culling the bounding box of the custom-object could be used. */ - return pchan_culling_test_simple(view, ob, pchan); -} - -static bool pchan_culling_test_wire(const DRWView *view, - const Object *ob, - const bPoseChannel *pchan) -{ - BLI_assert(((const bArmature *)ob->data)->drawtype == ARM_WIRE); - return pchan_culling_test_simple(view, ob, pchan); -} - -static bool pchan_culling_test_line(const DRWView *view, - const Object *ob, - const bPoseChannel *pchan) -{ - BLI_assert(((const bArmature *)ob->data)->drawtype == ARM_LINE); - /* Account for the end-points, as the line end-points size is in pixels, this is a rough value. - * Since the end-points are small the difference between having any margin or not is unlikely - * to be noticeable. */ - const float scale = 1.1f; - return pchan_culling_test_with_radius_scale(view, ob, pchan, scale); -} - -static bool pchan_culling_test_envelope(const DRWView *view, - const Object *ob, - const bPoseChannel *pchan) -{ - const bArmature *arm = ob->data; - BLI_assert(arm->drawtype == ARM_ENVELOPE); - UNUSED_VARS_NDEBUG(arm); - BoundSphere bsphere; - pchan_culling_calc_bsphere(ob, pchan, &bsphere); - bsphere.radius += max_ff(pchan->bone->rad_head, pchan->bone->rad_tail) * - mat4_to_size_max_axis(ob->obmat) * mat4_to_size_max_axis(pchan->disp_mat); - return DRW_culling_sphere_test(view, &bsphere); -} - -static bool pchan_culling_test_bbone(const DRWView *view, - const Object *ob, - const bPoseChannel *pchan) -{ - const bArmature *arm = ob->data; - BLI_assert(arm->drawtype == ARM_B_BONE); - UNUSED_VARS_NDEBUG(arm); - const float ob_scale = mat4_to_size_max_axis(ob->obmat); - const Mat4 *bbones_mat = (const Mat4 *)pchan->draw_data->bbone_matrix; - for (int i = pchan->bone->segments; i--; bbones_mat++) { - BoundSphere bsphere; - float size[3]; - mat4_to_size(size, bbones_mat->mat); - mul_v3_m4v3(bsphere.center, ob->obmat, bbones_mat->mat[3]); - bsphere.radius = len_v3(size) * ob_scale; - if (DRW_culling_sphere_test(view, &bsphere)) { - return true; - } - } - return false; -} - -static bool pchan_culling_test_octohedral(const DRWView *view, - const Object *ob, - const bPoseChannel *pchan) -{ - /* No type assertion as this is a fallback (files from the future will end up here). */ - /* Account for spheres on the end-points. */ - const float scale = 1.2f; - return pchan_culling_test_with_radius_scale(view, ob, pchan, scale); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \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(@campbellbarton): 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; - } - - boneflag &= ~BONE_DRAW_LOCKED_WEIGHT; - - if (!is_select) { - 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 (!is_select) { - 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, arm); - } - } - } - } - } -} - -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(); - bool draw_locked_weights = false; - - /* 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 won't become active). */ - ((draw_ctx->object_mode & OB_MODE_ALL_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; - } - } - - /* In weight paint mode retrieve the vertex group lock status. */ - if ((draw_ctx->object_mode & OB_MODE_ALL_WEIGHT_PAINT) && (draw_ctx->object_pose == ob) && - (draw_ctx->obact != NULL)) { - draw_locked_weights = true; - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - pchan->bone->flag &= ~BONE_DRAW_LOCKED_WEIGHT; - } - - const Object *obact_orig = DEG_get_original_object(draw_ctx->obact); - - const ListBase *defbase = BKE_object_defgroup_list(obact_orig); - LISTBASE_FOREACH (const bDeformGroup *, dg, defbase) { - if (dg->flag & DG_LOCK_WEIGHT) { - pchan = BKE_pose_channel_find_name(ob->pose, dg->name); - - if (pchan) { - pchan->bone->flag |= BONE_DRAW_LOCKED_WEIGHT; - } - } - } - } - - const DRWView *view = is_pose_select ? DRW_view_default_get() : NULL; - - 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); - } - - /* catch exception for bone with hidden parent */ - int 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; - } - - if (!draw_locked_weights) { - boneflag &= ~BONE_DRAW_LOCKED_WEIGHT; - } - - if (!is_pose_select) { - draw_bone_relations(ctx, NULL, pchan, arm, boneflag, constflag); - } - - if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) { - draw_bone_update_disp_matrix_custom(pchan); - if (!is_pose_select || pchan_culling_test_custom(view, ob, 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); - if (!is_pose_select || pchan_culling_test_envelope(view, ob, 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); - if (!is_pose_select || pchan_culling_test_line(view, ob, 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); - if (!is_pose_select || pchan_culling_test_wire(view, ob, 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); - if (!is_pose_select || pchan_culling_test_bbone(view, ob, pchan)) { - draw_bone_box(ctx, NULL, pchan, arm, boneflag, constflag, select_id); - } - } - else { - draw_bone_update_disp_matrix_default(NULL, pchan); - if (!is_pose_select || pchan_culling_test_octohedral(view, ob, pchan)) { - draw_bone_octahedral(ctx, NULL, pchan, arm, boneflag, constflag, select_id); - } - } - - /* These aren't included in the selection. */ - if (!is_pose_select) { - 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); - } - } - } - } - } - - arm->flag &= ~ARM_POSEMODE; -} - -static void armature_context_setup(ArmatureDrawContext *ctx, - OVERLAY_PrivateData *pd, - Object *ob, - const bool do_envelope_dist, - const bool is_edit_mode, - const bool is_pose_mode, - const float *const_color) -{ - const bool is_object_mode = !do_envelope_dist; - const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0 || - (pd->armature.do_pose_xray && is_pose_mode); - const bool draw_as_wire = (ob->dt < OB_SOLID); - const bool is_filled = (!pd->armature.transparent && !draw_as_wire) || !is_object_mode; - const bool is_transparent = pd->armature.transparent || (draw_as_wire && !is_object_mode); - bArmature *arm = ob->data; - OVERLAY_ArmatureCallBuffers *cbo = &pd->armature_call_buffers[is_xray]; - OVERLAY_ArmatureCallBuffersInner *cb = is_transparent ? &cbo->transp : &cbo->solid; - - static const float select_const_color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - - switch (arm->drawtype) { - case ARM_ENVELOPE: - ctx->envelope_outline = cb->envelope_outline; - ctx->envelope_solid = (is_filled) ? cb->envelope_fill : 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_fill : NULL; - break; - case ARM_OCTA: - ctx->outline = cb->octa_outline; - ctx->solid = (is_filled) ? cb->octa_fill : 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_fill : NULL; - ctx->point_outline = cb->point_outline; - ctx->custom_solid = (is_filled) ? cb->custom_fill : NULL; - ctx->custom_outline = cb->custom_outline; - ctx->custom_wire = cb->custom_wire; - ctx->custom_shapes_ghash = cb->custom_shapes_ghash; - ctx->show_relations = pd->armature.show_relations; - ctx->do_relations = !DRW_state_is_select() && pd->armature.show_relations && - (is_edit_mode | is_pose_mode); - ctx->const_color = DRW_state_is_select() ? select_const_color : const_color; - ctx->const_wire = ((((ob->base_flag & BASE_SELECTED) && (pd->v3d_flag & V3D_SELECT_OUTLINE)) || - (arm->drawtype == ARM_WIRE)) ? - 1.5f : - ((!is_filled || is_transparent) ? 1.0f : 0.0f)); -} - -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, 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, false, 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; - - if (ob->dt == OB_BOUNDBOX) { - return; - } - - DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); - armature_context_setup(&arm_ctx, pd, ob, false, false, false, color); - draw_armature_pose(&arm_ctx); -} - -static bool POSE_is_driven_by_active_armature(Object *ob) -{ - Object *ob_arm = BKE_modifiers_is_deformed_by_armature(ob); - if (ob_arm) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - bool is_active = OVERLAY_armature_is_pose_mode(ob_arm, draw_ctx); - return is_active; - } - - Object *ob_mesh_deform = BKE_modifiers_is_deformed_by_meshdeform(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].solid.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].solid.custom_shapes_ghash, NULL, NULL); - BLI_ghash_free(pd->armature_call_buffers[i].transp.custom_shapes_ghash, NULL, NULL); - } - } -} - -void OVERLAY_armature_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - DRW_draw_pass(psl->armature_transp_ps[0]); - 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_state_is_select()) { - DRW_draw_pass(psl->armature_transp_ps[1]); - DRW_draw_pass(psl->armature_ps[1]); - } -} - -void OVERLAY_pose_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_FramebufferList *fbl = vedata->fbl; - - if (psl->armature_bone_select_ps != NULL) { - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_default_fb); - } - - DRW_draw_pass(psl->armature_bone_select_ps); - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_line_in_front_fb); - GPU_framebuffer_clear_depth(fbl->overlay_line_in_front_fb, 1.0f); - } - - DRW_draw_pass(psl->armature_transp_ps[1]); - DRW_draw_pass(psl->armature_ps[1]); - } -} - -/** \} */ diff --git a/source/blender/draw/engines/overlay/overlay_armature.cc b/source/blender/draw/engines/overlay/overlay_armature.cc new file mode 100644 index 00000000000..1e10fc7cd20 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_armature.cc @@ -0,0 +1,2646 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include +#include +#include + +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_view3d_types.h" + +#include "DRW_render.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_deform.h" +#include "BKE_modifier.h" +#include "BKE_object.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.hh" + +#include "draw_cache_impl.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; + + /* 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; + +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 != nullptr) && (draw_ctx->object_mode & OB_MODE_ALL_WEIGHT_PAINT)) { + 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(); + const bool is_select_mode = DRW_state_is_select(); + 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) && + !is_select_mode; + pd->armature.do_pose_xray = (pd->overlay.flag & V3D_OVERLAY_BONE_SELECT) != 0; + pd->armature.do_pose_fade_geom = pd->armature.do_pose_xray && + ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) == 0) && + draw_ctx->object_pose != nullptr; + + const float wire_alpha = pd->overlay.bone_wire_alpha; + const bool use_wire_alpha = (wire_alpha < 1.0f); + + DRWState 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); + float4 color = {0.0f, 0.0f, 0.0f, alpha}; + DRW_shgroup_uniform_vec4_copy(grp, "color", color); + + pd->armature_bone_select_grp = grp = DRW_shgroup_create(sh, psl->armature_bone_select_ps); + color = {0.0f, 0.0f, 0.0f, powf(alpha, 4)}; + DRW_shgroup_uniform_vec4_copy(grp, "color", color); + } + + for (int i = 0; i < 2; i++) { + struct GPUShader *sh; + struct GPUVertFormat *format; + DRWShadingGroup *grp = nullptr; + + OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get(); + OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[i]; + + cb->solid.custom_shapes_ghash = BLI_ghash_ptr_new(__func__); + cb->transp.custom_shapes_ghash = BLI_ghash_ptr_new(__func__); + + DRWPass **p_armature_ps = &psl->armature_ps[i]; + DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : + DRWState(0); + state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_DEPTH; + DRW_PASS_CREATE(*p_armature_ps, state | pd->clipping_state | infront_state); + DRWPass *armature_ps = *p_armature_ps; + + DRWPass **p_armature_trans_ps = &psl->armature_transp_ps[i]; + state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ADD; + DRW_PASS_CREATE(*p_armature_trans_ps, state | pd->clipping_state); + DRWPass *armature_transp_ps = *p_armature_trans_ps; + +#define BUF_INSTANCE DRW_shgroup_call_buffer_instance +#define BUF_LINE(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_LINES) +#define BUF_POINT(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_POINTS) + + { + format = formats->instance_bone; + + sh = OVERLAY_shader_armature_sphere(false); + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); + cb->solid.point_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get()); + + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); + DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.4f); + cb->transp.point_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get()); + + sh = OVERLAY_shader_armature_shape(false); + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); + cb->solid.custom_fill = grp; + cb->solid.box_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get()); + cb->solid.octa_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get()); + + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); + DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.6f); + cb->transp.custom_fill = grp; + cb->transp.box_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get()); + cb->transp.octa_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get()); + + sh = OVERLAY_shader_armature_sphere(true); + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); + cb->solid.point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get()); + + if (use_wire_alpha) { + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); + cb->transp.point_outline = BUF_INSTANCE( + grp, format, DRW_cache_bone_point_wire_outline_get()); + } + else { + cb->transp.point_outline = cb->solid.point_outline; + } + + sh = OVERLAY_shader_armature_shape(true); + cb->solid.custom_outline = grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); + cb->solid.box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get()); + cb->solid.octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get()); + + if (use_wire_alpha) { + cb->transp.custom_outline = grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); + cb->transp.box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get()); + cb->transp.octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get()); + } + else { + cb->transp.custom_outline = cb->solid.custom_outline; + cb->transp.box_outline = cb->solid.box_outline; + cb->transp.octa_outline = cb->solid.octa_outline; + } + + sh = OVERLAY_shader_armature_shape_wire(); + cb->solid.custom_wire = grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); + + if (use_wire_alpha) { + cb->transp.custom_wire = grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); + } + else { + cb->transp.custom_wire = cb->solid.custom_wire; + } + } + { + format = formats->instance_extra; + + sh = OVERLAY_shader_armature_degrees_of_freedom_wire(); + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); + cb->solid.dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get()); + + if (use_wire_alpha) { + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); + cb->transp.dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get()); + } + else { + cb->transp.dof_lines = cb->solid.dof_lines; + } + + sh = OVERLAY_shader_armature_degrees_of_freedom_solid(); + grp = DRW_shgroup_create(sh, armature_transp_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); + cb->solid.dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get()); + + if (use_wire_alpha) { + grp = DRW_shgroup_create(sh, armature_transp_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); + cb->transp.dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get()); + } + else { + cb->transp.dof_sphere = cb->solid.dof_sphere; + } + } + { + format = formats->instance_bone_stick; + + sh = OVERLAY_shader_armature_stick(); + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); + cb->solid.stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get()); + + if (use_wire_alpha) { + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); + cb->transp.stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get()); + } + else { + cb->transp.stick = cb->solid.stick; + } + } + { + format = formats->instance_bone_envelope; + + sh = OVERLAY_shader_armature_envelope(false); + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_state_enable(grp, DRW_STATE_CULL_BACK); + DRW_shgroup_uniform_bool_copy(grp, "isDistance", false); + DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); + cb->solid.envelope_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get()); + + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA | DRW_STATE_CULL_BACK); + DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.6f); + cb->transp.envelope_fill = 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_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); + cb->solid.envelope_outline = BUF_INSTANCE( + grp, format, DRW_cache_bone_envelope_outline_get()); + + if (use_wire_alpha) { + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); + cb->transp.envelope_outline = BUF_INSTANCE( + grp, format, DRW_cache_bone_envelope_outline_get()); + } + else { + cb->transp.envelope_outline = cb->solid.envelope_outline; + } + + format = formats->instance_bone_envelope_distance; + + sh = OVERLAY_shader_armature_envelope(false); + grp = DRW_shgroup_create(sh, armature_transp_ps); + DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); + DRW_shgroup_uniform_bool_copy(grp, "isDistance", true); + DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT); + cb->solid.envelope_distance = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get()); + + if (use_wire_alpha) { + grp = DRW_shgroup_create(sh, armature_transp_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); + DRW_shgroup_uniform_bool_copy(grp, "isDistance", true); + DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT); + cb->transp.envelope_distance = BUF_INSTANCE( + grp, format, DRW_cache_bone_envelope_solid_get()); + } + else { + cb->transp.envelope_distance = cb->solid.envelope_distance; + } + } + { + format = formats->pos_color; + + sh = OVERLAY_shader_armature_wire(); + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f); + cb->solid.wire = BUF_LINE(grp, format); + + if (use_wire_alpha) { + grp = DRW_shgroup_create(sh, armature_ps); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha); + cb->transp.wire = BUF_LINE(grp, format); + } + else { + cb->transp.wire = cb->solid.wire; + } + } + } +} + +/* -------------------------------------------------------------------- */ +/** \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); + float obscale = mat4_to_scale(ctx->ob->obmat); + head_sph[3] = *radius_head * obscale; + head_sph[3] += *distance * obscale; + tail_sph[3] = *radius_tail * obscale; + tail_sph[3] += *distance * obscale; + 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); + float obscale = mat4_to_scale(ctx->ob->obmat); + head_sph[3] = *radius_head * obscale; + tail_sph[3] = *radius_tail * obscale; + + 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 "C" void drw_batch_cache_validate(Object *custom); +extern "C" void drw_batch_cache_generate_requested_delayed(Object *custom); + +BLI_INLINE DRWCallBuffer *custom_bone_instance_shgroup(ArmatureDrawContext *ctx, + DRWShadingGroup *grp, + struct GPUBatch *custom_geom) +{ + DRWCallBuffer *buf = static_cast( + BLI_ghash_lookup(ctx->custom_shapes_ghash, custom_geom)); + if (buf == nullptr) { + 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_mesh(ArmatureDrawContext *ctx, + Mesh *mesh, + 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_mesh_batch_cache_validate(custom, mesh); + + struct GPUBatch *surf = DRW_mesh_batch_cache_get_surface(mesh); + struct GPUBatch *edges = DRW_mesh_batch_cache_get_edge_detection(mesh, nullptr); + struct GPUBatch *ledges = DRW_mesh_batch_cache_get_loose_edges(mesh); + 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_delayed(custom); +} + +static void drw_shgroup_bone_custom_mesh_wire(ArmatureDrawContext *ctx, + Mesh *mesh, + 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_mesh_batch_cache_validate(custom, mesh); + + struct GPUBatch *geom = DRW_mesh_batch_cache_get_all_edges(mesh); + 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_delayed(custom); +} + +static void drw_shgroup_custom_bone_curve(ArmatureDrawContext *ctx, + Curve *curve, + const float (*bone_mat)[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_curve_batch_cache_validate(curve); + + /* This only handles curves without any surface. The other curve types should have been converted + * to meshes and rendered in the mesh drawing function. */ + struct GPUBatch *ledges = nullptr; + if (custom->type == OB_FONT) { + ledges = DRW_cache_text_edge_wire_get(custom); + } + else { + ledges = DRW_cache_curve_edge_wire_get(custom); + } + + if (ledges) { + BoneInstanceData inst_data; + mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat); + + DRWCallBuffer *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_delayed(custom); +} + +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) +{ + /* The custom object is not an evaluated object, so its object->data field hasn't been replaced + * by #data_eval. This is bad since it gives preference to an object's evaluated mesh over any + * other data type, but supporting all evaluated geometry components would require a much + * larger refactor of this area. */ + Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(custom); + if (mesh != nullptr) { + drw_shgroup_bone_custom_solid_mesh( + ctx, mesh, bone_mat, bone_color, hint_color, outline_color, custom); + return; + } + + if (ELEM(custom->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) { + drw_shgroup_custom_bone_curve( + ctx, static_cast(custom->data), bone_mat, outline_color, custom); + } +} + +static void drw_shgroup_bone_custom_wire(ArmatureDrawContext *ctx, + const float (*bone_mat)[4], + const float color[4], + Object *custom) +{ + /* See comments in #drw_shgroup_bone_custom_solid. */ + Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(custom); + if (mesh != nullptr) { + drw_shgroup_bone_custom_mesh_wire(ctx, mesh, bone_mat, color, custom); + return; + } + + if (ELEM(custom->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) { + drw_shgroup_custom_bone_curve( + ctx, static_cast(custom->data), bone_mat, color, custom); + } +} + +static void drw_shgroup_bone_custom_empty(ArmatureDrawContext *ctx, + const float (*bone_mat)[4], + const float color[4], + Object *custom) +{ + const 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, G_draw.block.color_wire); +} + +static void drw_shgroup_bone_ik_lines(ArmatureDrawContext *ctx, + const float start[3], + const float end[3]) +{ + drw_shgroup_bone_relationship_lines_ex(ctx, start, end, G_draw.block.color_bone_ik_line); +} + +static void drw_shgroup_bone_ik_no_target_lines(ArmatureDrawContext *ctx, + const float start[3], + const float end[3]) +{ + drw_shgroup_bone_relationship_lines_ex( + ctx, start, end, G_draw.block.color_bone_ik_line_no_target); +} + +static void drw_shgroup_bone_ik_spline_lines(ArmatureDrawContext *ctx, + const float start[3], + const float end[3]) +{ + drw_shgroup_bone_relationship_lines_ex(ctx, start, end, G_draw.block.color_bone_ik_line_spline); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \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) */ +}; + +/* 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 : nullptr; + bArmature *arm = (ob) ? static_cast(ob->data) : nullptr; + bActionGroup *grp = nullptr; + short color_index = 0; + + /* sanity check */ + if (ELEM(nullptr, ob, arm, pose, pchan)) { + ctx->bcolor = nullptr; + 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 its 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 nullptr, 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 != nullptr here) */ + ctx->bcolor = &grp->cs; + } + else { + ctx->bcolor = nullptr; + } +} + +/* 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; +} + +/* 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); + /* Meh, hardcoded srgb transform here. */ + srgb_to_linearrgb_v4(fcolor, fcolor); + } + else { + if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) { + copy_v4_v4(fcolor, G_draw.block.color_bone_pose_active); + } + else if (boneflag & BONE_DRAW_ACTIVE) { + copy_v4_v4(fcolor, G_draw.block.color_bone_pose_active_unsel); + } + else if (boneflag & BONE_SELECTED) { + copy_v4_v4(fcolor, G_draw.block.color_bone_pose); + } + else { + copy_v4_v4(fcolor, G_draw.block.color_wire); + } + } + return true; + } + case PCHAN_COLOR_SOLID: { + if (bcolor) { + rgb_uchar_to_float(fcolor, (uchar *)bcolor->solid); + fcolor[3] = 1.0f; + /* Meh, hardcoded srgb transform here. */ + srgb_to_linearrgb_v4(fcolor, fcolor); + } + else { + copy_v4_v4(fcolor, G_draw.block.color_bone_solid); + } + return true; + } + case PCHAN_COLOR_CONSTS: { + if ((bcolor == nullptr) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS)) { + if (constflag & PCHAN_HAS_TARGET) { + copy_v4_v4(fcolor, G_draw.block.color_bone_pose_target); + } + else if (constflag & PCHAN_HAS_IK) { + copy_v4_v4(fcolor, G_draw.block.color_bone_pose_ik); + } + else if (constflag & PCHAN_HAS_SPLINEIK) { + copy_v4_v4(fcolor, G_draw.block.color_bone_pose_spline_ik); + } + else if (constflag & PCHAN_HAS_CONST) { + copy_v4_v4(fcolor, G_draw.block.color_bone_pose_constraint); + } + else { + return false; + } + return true; + } + return false; + } + } + + return false; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Drawing Color Helpers + * \{ */ + +static void bone_locked_color_shade(float color[4]) +{ + float *locked_color = G_draw.block.color_bone_locked; + + interp_v3_v3v3(color, color, locked_color, locked_color[3]); +} + +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 G_draw.block.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); + + if (boneflag & BONE_DRAW_LOCKED_WEIGHT) { + bone_locked_color_shade(disp_color); + } + + return disp_color; + } + + return G_draw.block.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 G_draw.block.color_bone_solid; + } + + const float *col = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag); + + static float consts_color[4]; + if ((arm->flag & ARM_POSEMODE) && !(boneflag & BONE_DRAW_LOCKED_WEIGHT) && + 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; + } + if (boneflag & (BONE_DRAW_ACTIVE | BONE_SELECTED)) { + return 2.0f; + } + + 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, G_draw.block.color_bone_active); + } + else { + copy_v3_v3(disp_color, G_draw.block.color_bone_select); + } + } + else { + if (boneflag & BONE_DRAW_ACTIVE) { + copy_v3_v3(disp_color, G_draw.block.color_bone_active_unsel); + } + else { + copy_v3_v3(disp_color, G_draw.block.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); + + if (boneflag & BONE_DRAW_LOCKED_WEIGHT) { + bone_locked_color_shade(disp_color); + } + } + else { + copy_v3_v3(disp_color, G_draw.block.color_vertex); + } + + disp_color[3] = get_bone_wire_thickness(ctx, boneflag); + + return disp_color; +} + +static void bone_hint_color_shade(float hint_color[4], const float color[4]) +{ + /* Increase contrast. */ + mul_v3_v3v3(hint_color, color, color); + /* Decrease value to add mode shading to the shape. */ + mul_v3_fl(hint_color, 0.1f); + 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, G_draw.block.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 != nullptr) { + if (pchan->draw_data->bbone_matrix_len != pchan->bone->segments) { + MEM_SAFE_FREE(pchan->draw_data); + } + } + + if (pchan->draw_data == nullptr) { + pchan->draw_data = static_cast( + 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 ebmat[4][4]; + float bone_scale[3]; + 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) { + bone_mat = pchan->pose_mat; + disp_mat = pchan->disp_mat; + disp_tail_mat = pchan->disp_tail_mat; + copy_v3_fl(bone_scale, pchan->bone->length); + } + else { + eBone->length = len_v3v3(eBone->tail, eBone->head); + ED_armature_ebone_to_mat4(eBone, ebmat); + + copy_v3_fl(bone_scale, eBone->length); + bone_mat = ebmat; + disp_mat = eBone->disp_mat; + disp_tail_mat = eBone->disp_tail_mat; + } + + copy_m4_m4(disp_mat, bone_mat); + rescale_m4(disp_mat, bone_scale); + 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 = static_cast(arm->edbo->first); eBone; eBone = eBone->next) { + eBone->bbone_child = nullptr; + } + + for (eBone = static_cast(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, const float result_array[MAX_BBONE_SUBDIV][4][4]) +{ + BBoneSplineParameters param; + EditBone *prev, *next; + float imat[4][4], bonemat[4][4]; + float tmp[3]; + + memset(¶m, 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 = nullptr; + } + } + 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->bbone_flag & BBONE_ADD_PARENT_END_ROLL)) { + param.roll1 += prev->roll2; + } + + copy_v3_v3(param.scale_in, ebone->scale_in); + copy_v3_v3(param.scale_out, ebone->scale_out); + + param.curve_in_x = ebone->curve_in_x; + param.curve_in_z = ebone->curve_in_z; + + param.curve_out_x = ebone->curve_out_x; + param.curve_out_z = ebone->curve_out_z; + + if (ebone->bbone_flag & BBONE_SCALE_EASING) { + param.ease1 *= param.scale_in[1]; + param.curve_in_x *= param.scale_in[1]; + param.curve_in_z *= param.scale_in[1]; + + param.ease2 *= param.scale_out[1]; + param.curve_out_x *= param.scale_out[1]; + param.curve_out_z *= param.scale_out[1]; + } + + ebone->segments = BKE_pchan_bbone_spline_compute(¶m, 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; + } + + const float3 size_vec = {xwidth, length / bbone_segments, zwidth}; + size_to_mat4(s, size_vec); + + /* 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 bone_scale[3]; + float(*bone_mat)[4]; + float(*disp_mat)[4]; + float(*disp_tail_mat)[4]; + float rot_mat[3][3]; + + /* See TODO: above. */ + mul_v3_v3fl(bone_scale, pchan->custom_scale_xyz, PCHAN_CUSTOM_BONE_LENGTH(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; + + eulO_to_mat3(rot_mat, pchan->custom_rotation_euler, ROT_MODE_XYZ); + + copy_m4_m4(disp_mat, bone_mat); + translate_m4(disp_mat, + pchan->custom_translation[0], + pchan->custom_translation[1], + pchan->custom_translation[2]); + mul_m4_m4m3(disp_mat, disp_mat, rot_mat); + rescale_m4(disp_mat, bone_scale); + 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, + const EditBone *eBone, + const bPoseChannel *pchan, + const bArmature *arm) +{ + float final_col[4]; + const float *col = (ctx->const_color) ? ctx->const_color : + (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? &G_draw.block.color_text_hi.x : + &G_draw.block.color_text.x; + 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.1 : 0.65; + + if (pchan && pchan->custom && !(arm->flag & ARM_NO_CUSTOM)) { + /* Special case: Custom bones can have different scale than the bone. + * Recompute display matrix without the custom scaling applied. (T65640). */ + float axis_mat[4][4]; + float length = pchan->bone->length; + copy_m4_m4(axis_mat, pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat); + const float3 length_vec = {length, length, length}; + rescale_m4(axis_mat, length_vec); + translate_m4(axis_mat, 0.0, arm->axes_position - 1.0, 0.0); + + drw_shgroup_bone_axes(ctx, axis_mat, final_col); + } + else { + float disp_mat[4][4]; + copy_m4_m4(disp_mat, BONE_VAR(eBone, pchan, disp_mat)); + translate_m4(disp_mat, 0.0, arm->axes_position - 1.0, 0.0); + drw_shgroup_bone_axes(ctx, 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, G_draw.block.color_bone_solid); + copy_v4_v4(col_solid_tail, G_draw.block.color_bone_solid); + copy_v4_v4(col_wire_root, (ctx->const_color) ? ctx->const_color : &G_draw.block.color_vertex.x); + copy_v4_v4(col_wire_tail, (ctx->const_color) ? ctx->const_color : &G_draw.block.color_vertex.x); + + 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, G_draw.block.color_vertex_select); + } + if (eBone->flag & BONE_TIPSEL) { + copy_v3_v3(col_wire_tail, G_draw.block.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 && (boneflag & BONE_CONNECTED)) : + (pchan->bone->parent && (boneflag & 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 && (boneflag & BONE_DRAW_LOCKED_WEIGHT) == 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 != nullptr) { + 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 = G_draw.block.color_vertex_select; + } + if (boneflag & BONE_SELECTED) { + col_bone = G_draw.block.color_bone_active; + } + col_wire = G_draw.block.color_wire; + } + + /* Draw root point if we are not connected to our parent. */ + if (!(eBone ? (eBone->parent && (boneflag & BONE_CONNECTED)) : + (pchan->bone->parent && (boneflag & BONE_CONNECTED)))) { + + if (eBone) { + col_head = (eBone->flag & BONE_ROOTSEL) ? &G_draw.block.color_vertex_select.x : 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 != nullptr); + + 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 != nullptr); + + 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 == nullptr) { + 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 rest-space. */ + 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 = nullptr, *line_end = nullptr; + + for (con = static_cast(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)); + + /* Color Management: Exception here as texts are drawn in sRGB space directly. */ + 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 Pose Bone Culling + * + * Used for selection since drawing many bones can be slow, see: T91253. + * + * Bounding spheres are used with margins added to ensure bones are included. + * An added margin is needed because #BKE_pchan_minmax only returns the bounds + * of the bones head & tail which doesn't account for parts of the bone users may select + * (octahedral spheres or envelope radius for example). + * \{ */ + +static void pchan_culling_calc_bsphere(const Object *ob, + const bPoseChannel *pchan, + BoundSphere *r_bsphere) +{ + float min[3], max[3]; + INIT_MINMAX(min, max); + BKE_pchan_minmax(ob, pchan, true, min, max); + mid_v3_v3v3(r_bsphere->center, min, max); + r_bsphere->radius = len_v3v3(min, r_bsphere->center); +} + +/** + * \return true when bounding sphere from `pchan` intersect the view. + * (same for other "test" functions defined here). + */ +static bool pchan_culling_test_simple(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + BoundSphere bsphere; + pchan_culling_calc_bsphere(ob, pchan, &bsphere); + return DRW_culling_sphere_test(view, &bsphere); +} + +static bool pchan_culling_test_with_radius_scale(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan, + const float scale) +{ + BoundSphere bsphere; + pchan_culling_calc_bsphere(ob, pchan, &bsphere); + bsphere.radius *= scale; + return DRW_culling_sphere_test(view, &bsphere); +} + +static bool pchan_culling_test_custom(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + /* For more aggressive culling the bounding box of the custom-object could be used. */ + return pchan_culling_test_simple(view, ob, pchan); +} + +static bool pchan_culling_test_wire(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + BLI_assert(((const bArmature *)ob->data)->drawtype == ARM_WIRE); + return pchan_culling_test_simple(view, ob, pchan); +} + +static bool pchan_culling_test_line(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + BLI_assert(((const bArmature *)ob->data)->drawtype == ARM_LINE); + /* Account for the end-points, as the line end-points size is in pixels, this is a rough value. + * Since the end-points are small the difference between having any margin or not is unlikely + * to be noticeable. */ + const float scale = 1.1f; + return pchan_culling_test_with_radius_scale(view, ob, pchan, scale); +} + +static bool pchan_culling_test_envelope(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + const bArmature *arm = static_cast(ob->data); + BLI_assert(arm->drawtype == ARM_ENVELOPE); + UNUSED_VARS_NDEBUG(arm); + BoundSphere bsphere; + pchan_culling_calc_bsphere(ob, pchan, &bsphere); + bsphere.radius += max_ff(pchan->bone->rad_head, pchan->bone->rad_tail) * + mat4_to_size_max_axis(ob->obmat) * mat4_to_size_max_axis(pchan->disp_mat); + return DRW_culling_sphere_test(view, &bsphere); +} + +static bool pchan_culling_test_bbone(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + const bArmature *arm = static_cast(ob->data); + BLI_assert(arm->drawtype == ARM_B_BONE); + UNUSED_VARS_NDEBUG(arm); + const float ob_scale = mat4_to_size_max_axis(ob->obmat); + const Mat4 *bbones_mat = (const Mat4 *)pchan->draw_data->bbone_matrix; + for (int i = pchan->bone->segments; i--; bbones_mat++) { + BoundSphere bsphere; + float size[3]; + mat4_to_size(size, bbones_mat->mat); + mul_v3_m4v3(bsphere.center, ob->obmat, bbones_mat->mat[3]); + bsphere.radius = len_v3(size) * ob_scale; + if (DRW_culling_sphere_test(view, &bsphere)) { + return true; + } + } + return false; +} + +static bool pchan_culling_test_octohedral(const DRWView *view, + const Object *ob, + const bPoseChannel *pchan) +{ + /* No type assertion as this is a fallback (files from the future will end up here). */ + /* Account for spheres on the end-points. */ + const float scale = 1.2f; + return pchan_culling_test_with_radius_scale(view, ob, pchan, scale); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \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(@campbellbarton): 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 = static_cast(ob_orig->data); + + edbo_compute_bbone_child(arm); + + for (eBone = static_cast(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; + } + + boneflag &= ~BONE_DRAW_LOCKED_WEIGHT; + + if (!is_select) { + draw_bone_relations(ctx, eBone, nullptr, arm, boneflag, constflag); + } + + if (arm->drawtype == ARM_ENVELOPE) { + draw_bone_update_disp_matrix_default(eBone, nullptr); + draw_bone_envelope(ctx, eBone, nullptr, arm, boneflag, constflag, select_id); + } + else if (arm->drawtype == ARM_LINE) { + draw_bone_update_disp_matrix_default(eBone, nullptr); + draw_bone_line(ctx, eBone, nullptr, arm, boneflag, constflag, select_id); + } + else if (arm->drawtype == ARM_WIRE) { + draw_bone_update_disp_matrix_bbone(eBone, nullptr); + draw_bone_wire(ctx, eBone, nullptr, arm, boneflag, constflag, select_id); + } + else if (arm->drawtype == ARM_B_BONE) { + draw_bone_update_disp_matrix_bbone(eBone, nullptr); + draw_bone_box(ctx, eBone, nullptr, arm, boneflag, constflag, select_id); + } + else { + draw_bone_update_disp_matrix_default(eBone, nullptr); + draw_bone_octahedral(ctx, eBone, nullptr, arm, boneflag, constflag, select_id); + } + + if (!is_select) { + if (show_text && (arm->flag & ARM_DRAWNAMES)) { + draw_bone_name(ctx, eBone, nullptr, arm, boneflag); + } + + if (arm->flag & ARM_DRAWAXES) { + draw_axes(ctx, eBone, nullptr, arm); + } + } + } + } + } +} + +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 = static_cast(ob->data); + bPoseChannel *pchan; + int index = -1; + const bool show_text = DRW_state_show_text(); + bool draw_locked_weights = false; + + /* We can't safely draw non-updated pose, might contain nullptr 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 won't become active). */ + ((draw_ctx->object_mode & OB_MODE_ALL_WEIGHT_PAINT) && + (draw_ctx->object_pose != nullptr))))) && + DRW_state_is_select(); + + if (is_pose_select) { + const Object *ob_orig = DEG_get_original_object(ob); + index = ob_orig->runtime.select_id; + } + } + + /* In weight paint mode retrieve the vertex group lock status. */ + if ((draw_ctx->object_mode & OB_MODE_ALL_WEIGHT_PAINT) && (draw_ctx->object_pose == ob) && + (draw_ctx->obact != nullptr)) { + draw_locked_weights = true; + + for (pchan = static_cast(ob->pose->chanbase.first); pchan; + pchan = pchan->next) { + pchan->bone->flag &= ~BONE_DRAW_LOCKED_WEIGHT; + } + + const Object *obact_orig = DEG_get_original_object(draw_ctx->obact); + + const ListBase *defbase = BKE_object_defgroup_list(obact_orig); + LISTBASE_FOREACH (const bDeformGroup *, dg, defbase) { + if (dg->flag & DG_LOCK_WEIGHT) { + pchan = BKE_pose_channel_find_name(ob->pose, dg->name); + + if (pchan) { + pchan->bone->flag |= BONE_DRAW_LOCKED_WEIGHT; + } + } + } + } + + const DRWView *view = is_pose_select ? DRW_view_default_get() : nullptr; + + for (pchan = static_cast(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); + } + + /* catch exception for bone with hidden parent */ + int 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; + } + + if (!draw_locked_weights) { + boneflag &= ~BONE_DRAW_LOCKED_WEIGHT; + } + + if (!is_pose_select) { + draw_bone_relations(ctx, nullptr, pchan, arm, boneflag, constflag); + } + + if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) { + draw_bone_update_disp_matrix_custom(pchan); + if (!is_pose_select || pchan_culling_test_custom(view, ob, pchan)) { + draw_bone_custom_shape(ctx, nullptr, pchan, arm, boneflag, constflag, select_id); + } + } + else if (arm->drawtype == ARM_ENVELOPE) { + draw_bone_update_disp_matrix_default(nullptr, pchan); + if (!is_pose_select || pchan_culling_test_envelope(view, ob, pchan)) { + draw_bone_envelope(ctx, nullptr, pchan, arm, boneflag, constflag, select_id); + } + } + else if (arm->drawtype == ARM_LINE) { + draw_bone_update_disp_matrix_default(nullptr, pchan); + if (!is_pose_select || pchan_culling_test_line(view, ob, pchan)) { + draw_bone_line(ctx, nullptr, pchan, arm, boneflag, constflag, select_id); + } + } + else if (arm->drawtype == ARM_WIRE) { + draw_bone_update_disp_matrix_bbone(nullptr, pchan); + if (!is_pose_select || pchan_culling_test_wire(view, ob, pchan)) { + draw_bone_wire(ctx, nullptr, pchan, arm, boneflag, constflag, select_id); + } + } + else if (arm->drawtype == ARM_B_BONE) { + draw_bone_update_disp_matrix_bbone(nullptr, pchan); + if (!is_pose_select || pchan_culling_test_bbone(view, ob, pchan)) { + draw_bone_box(ctx, nullptr, pchan, arm, boneflag, constflag, select_id); + } + } + else { + draw_bone_update_disp_matrix_default(nullptr, pchan); + if (!is_pose_select || pchan_culling_test_octohedral(view, ob, pchan)) { + draw_bone_octahedral(ctx, nullptr, pchan, arm, boneflag, constflag, select_id); + } + } + + /* These aren't included in the selection. */ + if (!is_pose_select) { + if (draw_dofs) { + draw_bone_degrees_of_freedom(ctx, pchan); + } + + if (show_text && (arm->flag & ARM_DRAWNAMES)) { + draw_bone_name(ctx, nullptr, pchan, arm, boneflag); + } + + if (arm->flag & ARM_DRAWAXES) { + draw_axes(ctx, nullptr, pchan, arm); + } + } + } + } + } + + arm->flag &= ~ARM_POSEMODE; +} + +static void armature_context_setup(ArmatureDrawContext *ctx, + OVERLAY_PrivateData *pd, + Object *ob, + const bool do_envelope_dist, + const bool is_edit_mode, + const bool is_pose_mode, + const float *const_color) +{ + const bool is_object_mode = !do_envelope_dist; + const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0 || + (pd->armature.do_pose_xray && is_pose_mode); + const bool draw_as_wire = (ob->dt < OB_SOLID); + const bool is_filled = (!pd->armature.transparent && !draw_as_wire) || !is_object_mode; + const bool is_transparent = pd->armature.transparent || (draw_as_wire && !is_object_mode); + bArmature *arm = static_cast(ob->data); + OVERLAY_ArmatureCallBuffers *cbo = &pd->armature_call_buffers[is_xray]; + OVERLAY_ArmatureCallBuffersInner *cb = is_transparent ? &cbo->transp : &cbo->solid; + + static const float select_const_color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + + switch (arm->drawtype) { + case ARM_ENVELOPE: + ctx->envelope_outline = cb->envelope_outline; + ctx->envelope_solid = (is_filled) ? cb->envelope_fill : nullptr; + ctx->envelope_distance = (do_envelope_dist) ? cb->envelope_distance : nullptr; + 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_fill : nullptr; + break; + case ARM_OCTA: + ctx->outline = cb->octa_outline; + ctx->solid = (is_filled) ? cb->octa_fill : nullptr; + 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_fill : nullptr; + ctx->point_outline = cb->point_outline; + ctx->custom_solid = (is_filled) ? cb->custom_fill : nullptr; + ctx->custom_outline = cb->custom_outline; + ctx->custom_wire = cb->custom_wire; + ctx->custom_shapes_ghash = cb->custom_shapes_ghash; + ctx->show_relations = pd->armature.show_relations; + ctx->do_relations = !DRW_state_is_select() && pd->armature.show_relations && + (is_edit_mode | is_pose_mode); + ctx->const_color = DRW_state_is_select() ? select_const_color : const_color; + ctx->const_wire = ((((ob->base_flag & BASE_SELECTED) && (pd->v3d_flag & V3D_SELECT_OUTLINE)) || + (arm->drawtype == ARM_WIRE)) ? + 1.5f : + ((!is_filled || is_transparent) ? 1.0f : 0.0f)); +} + +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, true, false, nullptr); + 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, false, true, nullptr); + 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; + + if (ob->dt == OB_BOUNDBOX) { + return; + } + + DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); + armature_context_setup(&arm_ctx, pd, ob, false, false, false, color); + draw_armature_pose(&arm_ctx); +} + +static bool POSE_is_driven_by_active_armature(Object *ob) +{ + Object *ob_arm = BKE_modifiers_is_deformed_by_armature(ob); + if (ob_arm) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + bool is_active = OVERLAY_armature_is_pose_mode(ob_arm, draw_ctx); + return is_active; + } + + Object *ob_mesh_deform = BKE_modifiers_is_deformed_by_meshdeform(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].solid.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].solid.custom_shapes_ghash, nullptr, nullptr); + BLI_ghash_free(pd->armature_call_buffers[i].transp.custom_shapes_ghash, nullptr, nullptr); + } + } +} + +void OVERLAY_armature_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + DRW_draw_pass(psl->armature_transp_ps[0]); + 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 == nullptr || DRW_state_is_select()) { + DRW_draw_pass(psl->armature_transp_ps[1]); + DRW_draw_pass(psl->armature_ps[1]); + } +} + +void OVERLAY_pose_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_FramebufferList *fbl = vedata->fbl; + + if (psl->armature_bone_select_ps != nullptr) { + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_default_fb); + } + + DRW_draw_pass(psl->armature_bone_select_ps); + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_line_in_front_fb); + GPU_framebuffer_clear_depth(fbl->overlay_line_in_front_fb, 1.0f); + } + + DRW_draw_pass(psl->armature_transp_ps[1]); + DRW_draw_pass(psl->armature_ps[1]); + } +} + +/** \} */ diff --git a/source/blender/draw/engines/overlay/overlay_background.c b/source/blender/draw/engines/overlay/overlay_background.c deleted file mode 100644 index 32bcd04e05b..00000000000 --- a/source/blender/draw/engines/overlay/overlay_background.c +++ /dev/null @@ -1,114 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2020 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "DRW_render.h" - -#include "UI_resources.h" - -#include "draw_manager_text.h" -#include "overlay_private.h" - -void OVERLAY_background_cache_init(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_PrivateData *pd = vedata->stl->pd; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene = draw_ctx->scene; - const RegionView3D *rv3d = draw_ctx->rv3d; - const BoundBox *bb = rv3d ? rv3d->clipbb : NULL; - const View3D *v3d = draw_ctx->v3d; - bool draw_clipping_bounds = (pd->clipping_state != 0); - - { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_BACKGROUND; - float color_override[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - int background_type; - - if (DRW_state_is_opengl_render() && !DRW_state_draw_background()) { - background_type = BG_SOLID; - color_override[3] = 1.0f; - } - else if (pd->space_type == SPACE_IMAGE) { - background_type = BG_SOLID_CHECKER; - } - else if (pd->space_type == SPACE_NODE) { - background_type = BG_MASK; - state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL; - } - else if (!DRW_state_draw_background()) { - background_type = BG_CHECKER; - } - else if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD && scene->world) { - background_type = BG_SOLID; - /* TODO(fclem): this is a scene referred linear color. we should convert - * it to display linear here. */ - copy_v3_v3(color_override, &scene->world->horr); - color_override[3] = 1.0f; - } - else if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_VIEWPORT && - v3d->shading.type <= OB_SOLID) { - background_type = BG_SOLID; - copy_v3_v3(color_override, v3d->shading.background_color); - color_override[3] = 1.0f; - } - else { - switch (UI_GetThemeValue(TH_BACKGROUND_TYPE)) { - case TH_BACKGROUND_GRADIENT_LINEAR: - background_type = BG_GRADIENT; - break; - case TH_BACKGROUND_GRADIENT_RADIAL: - background_type = BG_RADIAL; - break; - default: - case TH_BACKGROUND_SINGLE_COLOR: - background_type = BG_SOLID; - break; - } - } - - DRW_PASS_CREATE(psl->background_ps, state); - - GPUShader *sh = OVERLAY_shader_background(); - DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->background_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &dtxl->color); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_vec4_copy(grp, "colorOverride", color_override); - DRW_shgroup_uniform_int_copy(grp, "bgType", background_type); - DRW_shgroup_call_procedural_triangles(grp, NULL, 1); - } - - if (draw_clipping_bounds) { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | DRW_STATE_CULL_BACK; - DRW_PASS_CREATE(psl->clipping_frustum_ps, state); - - GPUShader *sh = OVERLAY_shader_clipbound(); - DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->clipping_frustum_ps); - DRW_shgroup_uniform_vec4_copy(grp, "color", G_draw.block.color_clipping_border); - DRW_shgroup_uniform_vec3(grp, "boundbox", &bb->vec[0][0], 8); - - struct GPUBatch *cube = DRW_cache_cube_get(); - DRW_shgroup_call(grp, cube, NULL); - } - else { - psl->clipping_frustum_ps = NULL; - } -} - -void OVERLAY_background_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - if (DRW_state_is_fbo()) { - if (psl->clipping_frustum_ps) { - DRW_draw_pass(psl->clipping_frustum_ps); - } - - DRW_draw_pass(psl->background_ps); - } -} diff --git a/source/blender/draw/engines/overlay/overlay_background.cc b/source/blender/draw/engines/overlay/overlay_background.cc new file mode 100644 index 00000000000..e8bae74c70a --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_background.cc @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2020 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "UI_resources.h" + +#include "draw_manager_text.h" +#include "overlay_private.hh" + +void OVERLAY_background_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + const RegionView3D *rv3d = draw_ctx->rv3d; + const BoundBox *bb = rv3d ? rv3d->clipbb : nullptr; + const View3D *v3d = draw_ctx->v3d; + bool draw_clipping_bounds = (pd->clipping_state != 0); + + { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_BACKGROUND; + float color_override[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + int background_type; + + if (DRW_state_is_opengl_render() && !DRW_state_draw_background()) { + background_type = BG_SOLID; + color_override[3] = 1.0f; + } + else if (pd->space_type == SPACE_IMAGE) { + background_type = BG_SOLID_CHECKER; + } + else if (pd->space_type == SPACE_NODE) { + background_type = BG_MASK; + state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL; + } + else if (!DRW_state_draw_background()) { + background_type = BG_CHECKER; + } + else if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD && scene->world) { + background_type = BG_SOLID; + /* TODO(fclem): this is a scene referred linear color. we should convert + * it to display linear here. */ + copy_v3_v3(color_override, &scene->world->horr); + color_override[3] = 1.0f; + } + else if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_VIEWPORT && + v3d->shading.type <= OB_SOLID) { + background_type = BG_SOLID; + copy_v3_v3(color_override, v3d->shading.background_color); + color_override[3] = 1.0f; + } + else { + switch (UI_GetThemeValue(TH_BACKGROUND_TYPE)) { + case TH_BACKGROUND_GRADIENT_LINEAR: + background_type = BG_GRADIENT; + break; + case TH_BACKGROUND_GRADIENT_RADIAL: + background_type = BG_RADIAL; + break; + default: + case TH_BACKGROUND_SINGLE_COLOR: + background_type = BG_SOLID; + break; + } + } + + DRW_PASS_CREATE(psl->background_ps, state); + + GPUShader *sh = OVERLAY_shader_background(); + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->background_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &dtxl->color); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_vec4_copy(grp, "colorOverride", color_override); + DRW_shgroup_uniform_int_copy(grp, "bgType", background_type); + DRW_shgroup_call_procedural_triangles(grp, nullptr, 1); + } + + if (draw_clipping_bounds) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | DRW_STATE_CULL_BACK; + DRW_PASS_CREATE(psl->clipping_frustum_ps, state); + + GPUShader *sh = OVERLAY_shader_clipbound(); + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->clipping_frustum_ps); + DRW_shgroup_uniform_vec4_copy(grp, "color", G_draw.block.color_clipping_border); + DRW_shgroup_uniform_vec3(grp, "boundbox", &bb->vec[0][0], 8); + + struct GPUBatch *cube = DRW_cache_cube_get(); + DRW_shgroup_call(grp, cube, nullptr); + } + else { + psl->clipping_frustum_ps = nullptr; + } +} + +void OVERLAY_background_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + if (DRW_state_is_fbo()) { + if (psl->clipping_frustum_ps) { + DRW_draw_pass(psl->clipping_frustum_ps); + } + + DRW_draw_pass(psl->background_ps); + } +} diff --git a/source/blender/draw/engines/overlay/overlay_edit_curve.c b/source/blender/draw/engines/overlay/overlay_edit_curve.c deleted file mode 100644 index 09e3c3410c3..00000000000 --- a/source/blender/draw/engines/overlay/overlay_edit_curve.c +++ /dev/null @@ -1,121 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * 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.handle_display != CURVE_HANDLE_NONE; - pd->edit_curve.handle_display = v3d->overlay.handle_display; - 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_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display); - 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_bool_copy(grp, "showCurveHandles", pd->edit_curve.show_handles); - DRW_shgroup_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display); - 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_DRAW_IN_FRONT) != 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); - 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); - 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; - OVERLAY_FramebufferList *fbl = vedata->fbl; - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_default_fb); - } - - 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); -} diff --git a/source/blender/draw/engines/overlay/overlay_edit_curve.cc b/source/blender/draw/engines/overlay/overlay_edit_curve.cc new file mode 100644 index 00000000000..b84eb9b3a43 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_edit_curve.cc @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "DNA_curve_types.h" + +#include "overlay_private.hh" + +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.handle_display != CURVE_HANDLE_NONE; + pd->edit_curve.handle_display = v3d->overlay.handle_display; + 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_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display); + 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_bool_copy(grp, "showCurveHandles", pd->edit_curve.show_handles); + DRW_shgroup_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display); + 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_DRAW_IN_FRONT) != 0; + + Curve *cu = static_cast(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); + 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); + 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; + OVERLAY_FramebufferList *fbl = vedata->fbl; + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_default_fb); + } + + 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); +} diff --git a/source/blender/draw/engines/overlay/overlay_edit_curves.cc b/source/blender/draw/engines/overlay/overlay_edit_curves.cc index 02e40ea0304..dab44c655a5 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_curves.cc +++ b/source/blender/draw/engines/overlay/overlay_edit_curves.cc @@ -11,7 +11,7 @@ #include "draw_cache_impl.h" -#include "overlay_private.h" +#include "overlay_private.hh" void OVERLAY_edit_curves_init(OVERLAY_Data *vedata) { diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c deleted file mode 100644 index 4d65cbc04ff..00000000000 --- a/source/blender/draw/engines/overlay/overlay_edit_mesh.c +++ /dev/null @@ -1,381 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "DRW_render.h" - -#include "ED_view3d.h" - -#include "DNA_mesh_types.h" - -#include "BKE_customdata.h" -#include "BKE_editmesh.h" -#include "BKE_object.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_PrivateData *pd = vedata->stl->pd; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - pd->edit_mesh.do_zbufclip = XRAY_FLAG_ENABLED(draw_ctx->v3d); - - /* Create view with depth offset */ - DRWView *default_view = (DRWView *)DRW_view_default_get(); - 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.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; - } - 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; - - /* 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); - DRW_shgroup_uniform_bool_copy(grp, - "isConstantScreenSizeNormals", - (flag & V3D_OVERLAY_EDIT_CONSTANT_SCREEN_SIZE_NORMALS) != 0); - DRW_shgroup_uniform_float_copy( - grp, "normalScreenSize", v3d->overlay.normals_constant_screen_size); - } - { - /* 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); - const bool do_smooth_wire = (U.gpu_flag & USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE) == 0; - DRWState state_common = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | - DRW_STATE_BLEND_ALPHA; - /* Faces */ - /* Cage geom needs an offset applied 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); - DRW_shgroup_uniform_bool_copy(grp, "do_smooth_wire", do_smooth_wire); - - /* Verts */ - state |= DRW_STATE_WRITE_DEPTH; - DRW_PASS_CREATE(psl->edit_mesh_verts_ps[i], state | pd->clipping_state); - int vert_mask[4] = {0xFF, 0xFF, 0xFF, 0xFF}; - - 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); - DRW_shgroup_uniform_ivec4_copy(grp, "dataMask", vert_mask); - - 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); - } - /* Face-dots */ - 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_uniform_ivec4_copy(grp, "dataMask", vert_mask); - 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) { - Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob); - Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob); - - has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_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_attrs(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 draw_as_solid = (ob->dt > OB_WIRE); - bool do_in_front = (ob->dtx & OB_DRAW_IN_FRONT) != 0; - bool do_occlude_wire = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 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_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 && draw_as_solid)) { - 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_attrs(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_attrs(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_attrs(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); - } - - 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->region, 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]); -} - -void OVERLAY_edit_mesh_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_PrivateData *pd = vedata->stl->pd; - OVERLAY_FramebufferList *fbl = vedata->fbl; - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_default_fb); - } - - 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 face-fill. */ - 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(NULL); - - 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]); - } - else { - DRW_draw_pass(psl->edit_mesh_normals_ps); - overlay_edit_mesh_draw_components(psl, pd, false); - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_in_front_fb); - } - - if (!DRW_pass_is_empty(psl->edit_mesh_depth_ps[IN_FRONT])) { - DRW_view_set_active(NULL); - 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_mesh.cc b/source/blender/draw/engines/overlay/overlay_edit_mesh.cc new file mode 100644 index 00000000000..4509fd53ed8 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.cc @@ -0,0 +1,382 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "ED_view3d.h" + +#include "DNA_mesh_types.h" + +#include "BKE_customdata.h" +#include "BKE_editmesh.h" +#include "BKE_object.h" + +#include "draw_cache_impl.h" +#include "draw_manager_text.h" + +#include "overlay_private.hh" + +#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_PrivateData *pd = vedata->stl->pd; + const DRWContextState *draw_ctx = DRW_context_state_get(); + + pd->edit_mesh.do_zbufclip = XRAY_FLAG_ENABLED(draw_ctx->v3d); + + /* Create view with depth offset */ + DRWView *default_view = (DRWView *)DRW_view_default_get(); + 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 = nullptr; + GPUShader *sh = nullptr; + DRWState state = DRWState(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.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; + } + 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; + + /* 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 : DRWState(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); + DRW_shgroup_uniform_bool_copy(grp, + "isConstantScreenSizeNormals", + (flag & V3D_OVERLAY_EDIT_CONSTANT_SCREEN_SIZE_NORMALS) != 0); + DRW_shgroup_uniform_float_copy( + grp, "normalScreenSize", v3d->overlay.normals_constant_screen_size); + } + { + /* 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); + const bool do_smooth_wire = (U.gpu_flag & USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE) == 0; + DRWState state_common = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | + DRW_STATE_BLEND_ALPHA; + /* Faces */ + /* Cage geom needs an offset applied 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); + DRW_shgroup_uniform_bool_copy(grp, "do_smooth_wire", do_smooth_wire); + + /* Verts */ + state |= DRW_STATE_WRITE_DEPTH; + DRW_PASS_CREATE(psl->edit_mesh_verts_ps[i], state | pd->clipping_state); + int vert_mask[4] = {0xFF, 0xFF, 0xFF, 0xFF}; + + 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); + DRW_shgroup_uniform_ivec4_copy(grp, "dataMask", vert_mask); + + 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); + } + /* Face-dots */ + 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_uniform_ivec4_copy(grp, "dataMask", vert_mask); + DRW_shgroup_state_enable(grp, DRW_STATE_WRITE_DEPTH); + } + else { + pd->edit_mesh_facedots_grp[i] = nullptr; + } + } +} + +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) { + Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob); + Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob); + + has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_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(me); + geom_tris = DRW_mesh_batch_cache_get_edit_triangles(me); + 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(me); + 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(me); + DRW_shgroup_call_instances_with_attrs(skin_roots_shgrp, ob, circle, skin_roots); + } + } + + if (fdot_shgrp) { + geom_fcenter = DRW_mesh_batch_cache_get_edit_facedots(me); + 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 = nullptr; + + bool draw_as_solid = (ob->dt > OB_WIRE); + bool do_in_front = (ob->dtx & OB_DRAW_IN_FRONT) != 0; + bool do_occlude_wire = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 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_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 && draw_as_solid)) { + 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(); + Mesh *me = static_cast(ob->data); + if (vnormals_do) { + geom = DRW_mesh_batch_cache_get_edit_vnors(me); + DRW_shgroup_call_instances_with_attrs(pd->edit_mesh_normals_grp, ob, normal_geom, geom); + } + if (lnormals_do) { + geom = DRW_mesh_batch_cache_get_edit_lnors(me); + DRW_shgroup_call_instances_with_attrs(pd->edit_mesh_normals_grp, ob, normal_geom, geom); + } + if (fnormals_do) { + geom = DRW_mesh_batch_cache_get_edit_facedots(me); + DRW_shgroup_call_instances_with_attrs(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); + } + + 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->region, 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]); +} + +void OVERLAY_edit_mesh_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + OVERLAY_FramebufferList *fbl = vedata->fbl; + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_default_fb); + } + + 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 face-fill. */ + 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(nullptr); + + 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]); + } + else { + DRW_draw_pass(psl->edit_mesh_normals_ps); + overlay_edit_mesh_draw_components(psl, pd, false); + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_in_front_fb); + } + + if (!DRW_pass_is_empty(psl->edit_mesh_depth_ps[IN_FRONT])) { + DRW_view_set_active(nullptr); + 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 deleted file mode 100644 index bd8720042f1..00000000000 --- a/source/blender/draw/engines/overlay/overlay_edit_text.c +++ /dev/null @@ -1,219 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "DRW_render.h" - -#include "UI_resources.h" - -#include "BKE_vfont.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.handle_display != CURVE_HANDLE_NONE; - pd->edit_curve.handle_display = v3d->overlay.handle_display; - 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.color_wire); - } - { - /* Cursor (text caret). */ - state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; - DRW_PASS_CREATE(psl->edit_text_cursor_ps, state | pd->clipping_state); - sh = OVERLAY_shader_uniform_color(); - pd->edit_text_cursor_grp = grp = DRW_shgroup_create(sh, psl->edit_text_cursor_ps); - DRW_shgroup_uniform_vec4(grp, "color", pd->edit_text.cursor_color, 1); - - /* Selection boxes. */ - state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; - DRW_PASS_CREATE(psl->edit_text_selection_ps, state | pd->clipping_state); - sh = OVERLAY_shader_uniform_color(); - pd->edit_text_selection_grp = grp = DRW_shgroup_create(sh, psl->edit_text_selection_ps); - DRW_shgroup_uniform_vec4(grp, "color", pd->edit_text.selection_color, 1); - - /* Highlight text within selection boxes. */ - state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | DRW_STATE_DEPTH_GREATER_EQUAL | - pd->clipping_state; - DRW_PASS_INSTANCE_CREATE(psl->edit_text_highlight_ps, psl->edit_text_selection_ps, state); - } - { - /* Create view which will render everything (hopefully) behind the text geometry. */ - DRWView *default_view = (DRWView *)DRW_view_default_get(); - pd->view_edit_text = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, -5.0f); - } -} - -/* 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(const 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_selection_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_cursor_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.color_active : G_draw.block.color_wire; - - 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; - struct GPUBatch *geom; - bool do_in_front = (ob->dtx & OB_DRAW_IN_FRONT) != 0; - - geom = DRW_cache_text_edge_wire_get(ob); - if (geom) { - DRW_shgroup_call(pd->edit_text_wire_grp[do_in_front], geom, ob); - } - - 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_PrivateData *pd = vedata->stl->pd; - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_FramebufferList *fbl = vedata->fbl; - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_default_fb); - } - - DRW_draw_pass(psl->edit_text_wire_ps[0]); - DRW_draw_pass(psl->edit_text_wire_ps[1]); - - DRW_view_set_active(pd->view_edit_text); - - /* Selection Boxes. */ - UI_GetThemeColor4fv(TH_WIDGET_TEXT_SELECTION, pd->edit_text.selection_color); - srgb_to_linearrgb_v4(pd->edit_text.selection_color, pd->edit_text.selection_color); - DRW_draw_pass(psl->edit_text_selection_ps); - - /* Highlight text within selection boxes. */ - UI_GetThemeColor4fv(TH_WIDGET_TEXT_HIGHLIGHT, pd->edit_text.selection_color); - srgb_to_linearrgb_v4(pd->edit_text.selection_color, pd->edit_text.selection_color); - DRW_draw_pass(psl->edit_text_highlight_ps); - - /* Cursor (text caret). */ - UI_GetThemeColor4fv(TH_WIDGET_TEXT_CURSOR, pd->edit_text.cursor_color); - srgb_to_linearrgb_v4(pd->edit_text.cursor_color, pd->edit_text.cursor_color); - DRW_draw_pass(psl->edit_text_cursor_ps); -} diff --git a/source/blender/draw/engines/overlay/overlay_edit_text.cc b/source/blender/draw/engines/overlay/overlay_edit_text.cc new file mode 100644 index 00000000000..f541619ccdd --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_edit_text.cc @@ -0,0 +1,219 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "UI_resources.h" + +#include "BKE_vfont.h" + +#include "DNA_curve_types.h" + +#include "overlay_private.hh" + +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.handle_display != CURVE_HANDLE_NONE; + pd->edit_curve.handle_display = v3d->overlay.handle_display; + 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.color_wire); + } + { + /* Cursor (text caret). */ + state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->edit_text_cursor_ps, state | pd->clipping_state); + sh = OVERLAY_shader_uniform_color(); + pd->edit_text_cursor_grp = grp = DRW_shgroup_create(sh, psl->edit_text_cursor_ps); + DRW_shgroup_uniform_vec4(grp, "color", pd->edit_text.cursor_color, 1); + + /* Selection boxes. */ + state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->edit_text_selection_ps, state | pd->clipping_state); + sh = OVERLAY_shader_uniform_color(); + pd->edit_text_selection_grp = grp = DRW_shgroup_create(sh, psl->edit_text_selection_ps); + DRW_shgroup_uniform_vec4(grp, "color", pd->edit_text.selection_color, 1); + + /* Highlight text within selection boxes. */ + state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | DRW_STATE_DEPTH_GREATER_EQUAL | + pd->clipping_state; + DRW_PASS_INSTANCE_CREATE(psl->edit_text_highlight_ps, psl->edit_text_selection_ps, state); + } + { + /* Create view which will render everything (hopefully) behind the text geometry. */ + DRWView *default_view = (DRWView *)DRW_view_default_get(); + pd->view_edit_text = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, -5.0f); + } +} + +/* 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(const 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 = static_cast(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_selection_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 = static_cast(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_cursor_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 = static_cast(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.color_active : G_draw.block.color_wire; + + 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; + struct GPUBatch *geom; + bool do_in_front = (ob->dtx & OB_DRAW_IN_FRONT) != 0; + + geom = DRW_cache_text_edge_wire_get(ob); + if (geom) { + DRW_shgroup_call(pd->edit_text_wire_grp[do_in_front], geom, ob); + } + + 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_PrivateData *pd = vedata->stl->pd; + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_FramebufferList *fbl = vedata->fbl; + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_default_fb); + } + + DRW_draw_pass(psl->edit_text_wire_ps[0]); + DRW_draw_pass(psl->edit_text_wire_ps[1]); + + DRW_view_set_active(pd->view_edit_text); + + /* Selection Boxes. */ + UI_GetThemeColor4fv(TH_WIDGET_TEXT_SELECTION, pd->edit_text.selection_color); + srgb_to_linearrgb_v4(pd->edit_text.selection_color, pd->edit_text.selection_color); + DRW_draw_pass(psl->edit_text_selection_ps); + + /* Highlight text within selection boxes. */ + UI_GetThemeColor4fv(TH_WIDGET_TEXT_HIGHLIGHT, pd->edit_text.selection_color); + srgb_to_linearrgb_v4(pd->edit_text.selection_color, pd->edit_text.selection_color); + DRW_draw_pass(psl->edit_text_highlight_ps); + + /* Cursor (text caret). */ + UI_GetThemeColor4fv(TH_WIDGET_TEXT_CURSOR, pd->edit_text.cursor_color); + srgb_to_linearrgb_v4(pd->edit_text.cursor_color, pd->edit_text.cursor_color); + DRW_draw_pass(psl->edit_text_cursor_ps); +} diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.c b/source/blender/draw/engines/overlay/overlay_edit_uv.c deleted file mode 100644 index d2737d73333..00000000000 --- a/source/blender/draw/engines/overlay/overlay_edit_uv.c +++ /dev/null @@ -1,586 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ -#include "DRW_render.h" - -#include "draw_cache_impl.h" -#include "draw_manager_text.h" - -#include "BKE_customdata.h" -#include "BKE_editmesh.h" -#include "BKE_image.h" -#include "BKE_layer.h" -#include "BKE_mask.h" -#include "BKE_object.h" -#include "BKE_paint.h" - -#include "DNA_brush_types.h" -#include "DNA_mesh_types.h" - -#include "DEG_depsgraph_query.h" - -#include "ED_image.h" - -#include "IMB_imbuf_types.h" - -#include "GPU_batch.h" - -#include "UI_interface.h" -#include "UI_resources.h" - -#include "overlay_private.h" - -/* Forward declarations. */ -static void overlay_edit_uv_cache_populate(OVERLAY_Data *vedata, Object *ob); - -typedef struct OVERLAY_StretchingAreaTotals { - void *next, *prev; - float *total_area; - float *total_area_uv; -} OVERLAY_StretchingAreaTotals; - -static OVERLAY_UVLineStyle edit_uv_line_style_from_space_image(const SpaceImage *sima) -{ - const bool is_uv_editor = sima->mode == SI_MODE_UV; - if (is_uv_editor) { - switch (sima->dt_uv) { - case SI_UVDT_OUTLINE: - return OVERLAY_UV_LINE_STYLE_OUTLINE; - case SI_UVDT_BLACK: - return OVERLAY_UV_LINE_STYLE_BLACK; - case SI_UVDT_WHITE: - return OVERLAY_UV_LINE_STYLE_WHITE; - case SI_UVDT_DASH: - return OVERLAY_UV_LINE_STYLE_DASH; - default: - return OVERLAY_UV_LINE_STYLE_BLACK; - } - } - else { - return OVERLAY_UV_LINE_STYLE_SHADOW; - } -} - -/* TODO(jbakker): the GPU texture should be cached with the mask. */ -static GPUTexture *edit_uv_mask_texture( - Mask *mask, const int width, const int height_, const float aspx, const float aspy) -{ - const int height = (float)height_ * (aspy / aspx); - MaskRasterHandle *handle; - float *buffer = MEM_mallocN(sizeof(float) * height * width, __func__); - - /* Initialize rasterization handle. */ - handle = BKE_maskrasterize_handle_new(); - BKE_maskrasterize_handle_init(handle, mask, width, height, true, true, true); - - BKE_maskrasterize_buffer(handle, width, height, buffer); - - /* Free memory. */ - BKE_maskrasterize_handle_free(handle); - GPUTexture *texture = GPU_texture_create_2d(mask->id.name, width, height, 1, GPU_R16F, buffer); - MEM_freeN(buffer); - return texture; -} - -/* -------------------------------------------------------------------- */ -/** \name Internal API - * \{ */ - -void OVERLAY_edit_uv_init(OVERLAY_Data *vedata) -{ - OVERLAY_StorageList *stl = vedata->stl; - OVERLAY_PrivateData *pd = stl->pd; - const DRWContextState *draw_ctx = DRW_context_state_get(); - SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; - const Scene *scene = draw_ctx->scene; - ToolSettings *ts = scene->toolsettings; - const Brush *brush = BKE_paint_brush(&ts->imapaint.paint); - const bool show_overlays = !pd->hide_overlays; - - Image *image = sima->image; - /* By design no image is an image type. This so editor shows UV's by default. */ - const bool is_image_type = - (image == NULL) || ELEM(image->type, IMA_TYPE_IMAGE, IMA_TYPE_MULTILAYER, IMA_TYPE_UV_TEST); - const bool is_uv_editor = sima->mode == SI_MODE_UV; - const bool has_edit_object = (draw_ctx->object_edit) != NULL; - const bool is_paint_mode = sima->mode == SI_MODE_PAINT; - const bool is_view_mode = sima->mode == SI_MODE_VIEW; - const bool is_mask_mode = sima->mode == SI_MODE_MASK; - const bool is_edit_mode = draw_ctx->object_mode == OB_MODE_EDIT; - const bool do_uv_overlay = is_image_type && is_uv_editor && has_edit_object; - const bool show_modified_uvs = sima->flag & SI_DRAWSHADOW; - const bool is_tiled_image = image && (image->source == IMA_SRC_TILED); - const bool do_edges_only = (ts->uv_flag & UV_SYNC_SELECTION) ? - /* NOTE: Ignore #SCE_SELECT_EDGE because a single selected edge - * on the mesh may cause single UV vertices to be selected. */ - false : - (ts->uv_selectmode == UV_SELECT_EDGE); - const bool do_faces = ((sima->flag & SI_NO_DRAWFACES) == 0); - const bool do_face_dots = (ts->uv_flag & UV_SYNC_SELECTION) ? - (ts->selectmode & SCE_SELECT_FACE) != 0 : - (ts->uv_selectmode == UV_SELECT_FACE); - const bool do_uvstretching_overlay = is_image_type && is_uv_editor && is_edit_mode && - ((sima->flag & SI_DRAW_STRETCH) != 0); - const bool do_tex_paint_shadows = (sima->flag & SI_NO_DRAW_TEXPAINT) == 0; - const bool do_stencil_overlay = is_paint_mode && is_image_type && brush && - (brush->imagepaint_tool == PAINT_TOOL_CLONE) && - brush->clone.image; - - pd->edit_uv.do_verts = show_overlays && (!do_edges_only); - pd->edit_uv.do_faces = show_overlays && do_faces && !do_uvstretching_overlay; - pd->edit_uv.do_face_dots = show_overlays && do_faces && do_face_dots; - pd->edit_uv.do_uv_overlay = show_overlays && do_uv_overlay; - pd->edit_uv.do_uv_shadow_overlay = show_overlays && is_image_type && - ((is_paint_mode && do_tex_paint_shadows && - ((draw_ctx->object_mode & - (OB_MODE_TEXTURE_PAINT | OB_MODE_EDIT)) != 0)) || - (is_view_mode && do_tex_paint_shadows && - ((draw_ctx->object_mode & (OB_MODE_TEXTURE_PAINT)) != 0)) || - (do_uv_overlay && (show_modified_uvs))); - - pd->edit_uv.do_mask_overlay = show_overlays && is_mask_mode && (sima->mask_info.mask != NULL) && - ((sima->mask_info.draw_flag & MASK_DRAWFLAG_OVERLAY) != 0); - pd->edit_uv.mask_overlay_mode = sima->mask_info.overlay_mode; - pd->edit_uv.mask = sima->mask_info.mask ? (Mask *)DEG_get_evaluated_id( - draw_ctx->depsgraph, &sima->mask_info.mask->id) : - NULL; - - pd->edit_uv.do_uv_stretching_overlay = show_overlays && do_uvstretching_overlay; - pd->edit_uv.uv_opacity = sima->uv_opacity; - pd->edit_uv.do_tiled_image_overlay = show_overlays && is_image_type && is_tiled_image; - pd->edit_uv.do_tiled_image_border_overlay = is_image_type && is_tiled_image; - pd->edit_uv.dash_length = 4.0f * UI_DPI_FAC; - pd->edit_uv.line_style = edit_uv_line_style_from_space_image(sima); - pd->edit_uv.do_smooth_wire = ((U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) != 0); - pd->edit_uv.do_stencil_overlay = show_overlays && do_stencil_overlay; - - pd->edit_uv.draw_type = sima->dt_uvstretch; - BLI_listbase_clear(&pd->edit_uv.totals); - pd->edit_uv.total_area_ratio = 0.0f; - - /* During engine initialization phase the `sima` isn't locked and - * we are able to retrieve the needed data. - * During cache_init the image engine locks the `sima` and makes it impossible - * to retrieve the data. */ - ED_space_image_get_uv_aspect(sima, &pd->edit_uv.uv_aspect[0], &pd->edit_uv.uv_aspect[1]); - ED_space_image_get_size(sima, &pd->edit_uv.image_size[0], &pd->edit_uv.image_size[1]); - ED_space_image_get_aspect(sima, &pd->edit_uv.image_aspect[0], &pd->edit_uv.image_aspect[1]); -} - -void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata) -{ - OVERLAY_StorageList *stl = vedata->stl; - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_PrivateData *pd = stl->pd; - - const DRWContextState *draw_ctx = DRW_context_state_get(); - SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; - Image *image = sima->image; - const Scene *scene = draw_ctx->scene; - ToolSettings *ts = scene->toolsettings; - - if (pd->edit_uv.do_uv_overlay || pd->edit_uv.do_uv_shadow_overlay) { - /* uv edges */ - { - DRW_PASS_CREATE(psl->edit_uv_edges_ps, - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - DRW_STATE_BLEND_ALPHA); - const bool do_edges_only = (ts->uv_flag & UV_SYNC_SELECTION) ? - false : - (ts->uv_selectmode & UV_SELECT_EDGE); - GPUShader *sh = do_edges_only ? OVERLAY_shader_edit_uv_edges_for_edge_select_get() : - OVERLAY_shader_edit_uv_edges_get(); - if (pd->edit_uv.do_uv_shadow_overlay) { - pd->edit_uv_shadow_edges_grp = DRW_shgroup_create(sh, psl->edit_uv_edges_ps); - DRW_shgroup_uniform_block(pd->edit_uv_shadow_edges_grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_int_copy( - pd->edit_uv_shadow_edges_grp, "lineStyle", OVERLAY_UV_LINE_STYLE_SHADOW); - DRW_shgroup_uniform_float_copy( - pd->edit_uv_shadow_edges_grp, "alpha", pd->edit_uv.uv_opacity); - DRW_shgroup_uniform_float( - pd->edit_uv_shadow_edges_grp, "dashLength", &pd->edit_uv.dash_length, 1); - DRW_shgroup_uniform_bool( - pd->edit_uv_shadow_edges_grp, "doSmoothWire", &pd->edit_uv.do_smooth_wire, 1); - } - - if (pd->edit_uv.do_uv_overlay) { - pd->edit_uv_edges_grp = DRW_shgroup_create(sh, psl->edit_uv_edges_ps); - DRW_shgroup_uniform_block(pd->edit_uv_edges_grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_int_copy(pd->edit_uv_edges_grp, "lineStyle", pd->edit_uv.line_style); - DRW_shgroup_uniform_float_copy(pd->edit_uv_edges_grp, "alpha", pd->edit_uv.uv_opacity); - DRW_shgroup_uniform_float( - pd->edit_uv_edges_grp, "dashLength", &pd->edit_uv.dash_length, 1); - DRW_shgroup_uniform_bool( - pd->edit_uv_edges_grp, "doSmoothWire", &pd->edit_uv.do_smooth_wire, 1); - } - } - } - - if (pd->edit_uv.do_uv_overlay) { - if (pd->edit_uv.do_verts || pd->edit_uv.do_face_dots) { - DRW_PASS_CREATE(psl->edit_uv_verts_ps, - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - DRW_STATE_BLEND_ALPHA); - } - - /* uv verts */ - if (pd->edit_uv.do_verts) { - GPUShader *sh = OVERLAY_shader_edit_uv_verts_get(); - pd->edit_uv_verts_grp = DRW_shgroup_create(sh, psl->edit_uv_verts_ps); - - const float point_size = UI_GetThemeValuef(TH_VERTEX_SIZE) * U.dpi_fac; - - DRW_shgroup_uniform_block(pd->edit_uv_verts_grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy( - pd->edit_uv_verts_grp, "pointSize", (point_size + 1.5f) * M_SQRT2); - DRW_shgroup_uniform_float_copy(pd->edit_uv_verts_grp, "outlineWidth", 0.75f); - float theme_color[4]; - UI_GetThemeColor4fv(TH_VERTEX, theme_color); - srgb_to_linearrgb_v4(theme_color, theme_color); - DRW_shgroup_uniform_vec4_copy(pd->edit_uv_verts_grp, "color", theme_color); - } - - /* uv faces */ - if (pd->edit_uv.do_faces) { - DRW_PASS_CREATE(psl->edit_uv_faces_ps, - DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA); - GPUShader *sh = OVERLAY_shader_edit_uv_face_get(); - pd->edit_uv_faces_grp = DRW_shgroup_create(sh, psl->edit_uv_faces_ps); - DRW_shgroup_uniform_block(pd->edit_uv_faces_grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float(pd->edit_uv_faces_grp, "uvOpacity", &pd->edit_uv.uv_opacity, 1); - } - - /* uv face dots */ - if (pd->edit_uv.do_face_dots) { - const float point_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) * U.dpi_fac; - GPUShader *sh = OVERLAY_shader_edit_uv_face_dots_get(); - pd->edit_uv_face_dots_grp = DRW_shgroup_create(sh, psl->edit_uv_verts_ps); - DRW_shgroup_uniform_block(pd->edit_uv_face_dots_grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float_copy(pd->edit_uv_face_dots_grp, "pointSize", point_size); - } - } - - /* uv stretching */ - if (pd->edit_uv.do_uv_stretching_overlay) { - DRW_PASS_CREATE(psl->edit_uv_stretching_ps, - DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA); - if (pd->edit_uv.draw_type == SI_UVDT_STRETCH_ANGLE) { - GPUShader *sh = OVERLAY_shader_edit_uv_stretching_angle_get(); - pd->edit_uv_stretching_grp = DRW_shgroup_create(sh, psl->edit_uv_stretching_ps); - DRW_shgroup_uniform_block(pd->edit_uv_stretching_grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_vec2_copy(pd->edit_uv_stretching_grp, "aspect", pd->edit_uv.uv_aspect); - } - else /* SI_UVDT_STRETCH_AREA */ { - GPUShader *sh = OVERLAY_shader_edit_uv_stretching_area_get(); - pd->edit_uv_stretching_grp = DRW_shgroup_create(sh, psl->edit_uv_stretching_ps); - DRW_shgroup_uniform_block(pd->edit_uv_stretching_grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_float( - pd->edit_uv_stretching_grp, "totalAreaRatio", &pd->edit_uv.total_area_ratio, 1); - } - } - - if (pd->edit_uv.do_tiled_image_border_overlay) { - GPUBatch *geom = DRW_cache_quad_wires_get(); - float obmat[4][4]; - unit_m4(obmat); - - DRW_PASS_CREATE(psl->edit_uv_tiled_image_borders_ps, - DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS); - GPUShader *sh = OVERLAY_shader_edit_uv_tiled_image_borders_get(); - - float theme_color[4], selected_color[4]; - UI_GetThemeColorShade4fv(TH_BACK, 60, theme_color); - UI_GetThemeColor4fv(TH_FACE_SELECT, selected_color); - srgb_to_linearrgb_v4(theme_color, theme_color); - srgb_to_linearrgb_v4(selected_color, selected_color); - - DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->edit_uv_tiled_image_borders_ps); - DRW_shgroup_uniform_vec4_copy(grp, "color", theme_color); - DRW_shgroup_uniform_vec3_copy(grp, "offset", (float[3]){0.0f, 0.0f, 0.0f}); - - LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { - const int tile_x = ((tile->tile_number - 1001) % 10); - const int tile_y = ((tile->tile_number - 1001) / 10); - obmat[3][1] = (float)tile_y; - obmat[3][0] = (float)tile_x; - DRW_shgroup_call_obmat(grp, geom, obmat); - } - /* Only mark active border when overlays are enabled. */ - if (pd->edit_uv.do_tiled_image_overlay) { - /* Active tile border */ - ImageTile *active_tile = BLI_findlink(&image->tiles, image->active_tile_index); - if (active_tile) { - obmat[3][0] = (float)((active_tile->tile_number - 1001) % 10); - obmat[3][1] = (float)((active_tile->tile_number - 1001) / 10); - grp = DRW_shgroup_create(sh, psl->edit_uv_tiled_image_borders_ps); - DRW_shgroup_uniform_vec4_copy(grp, "color", selected_color); - DRW_shgroup_call_obmat(grp, geom, obmat); - } - } - } - - if (pd->edit_uv.do_tiled_image_overlay) { - struct DRWTextStore *dt = DRW_text_cache_ensure(); - uchar color[4]; - /* Color Management: Exception here as texts are drawn in sRGB space directly. */ - UI_GetThemeColorShade4ubv(TH_BACK, 60, color); - char text[16]; - LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { - BLI_snprintf(text, 5, "%d", tile->tile_number); - float tile_location[3] = { - ((tile->tile_number - 1001) % 10), ((tile->tile_number - 1001) / 10), 0.0f}; - DRW_text_cache_add( - dt, tile_location, text, strlen(text), 10, 10, DRW_TEXT_CACHE_GLOBALSPACE, color); - } - } - - if (pd->edit_uv.do_stencil_overlay) { - const Brush *brush = BKE_paint_brush(&ts->imapaint.paint); - Image *stencil_image = brush->clone.image; - ImBuf *stencil_ibuf = BKE_image_acquire_ibuf(stencil_image, NULL, &pd->edit_uv.stencil_lock); - - if (stencil_ibuf == NULL) { - pd->edit_uv.stencil_ibuf = NULL; - pd->edit_uv.stencil_image = NULL; - } - else { - DRW_PASS_CREATE(psl->edit_uv_stencil_ps, - DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | - DRW_STATE_BLEND_ALPHA_PREMUL); - GPUShader *sh = OVERLAY_shader_edit_uv_stencil_image(); - GPUBatch *geom = DRW_cache_quad_get(); - DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->edit_uv_stencil_ps); - pd->edit_uv.stencil_ibuf = stencil_ibuf; - pd->edit_uv.stencil_image = stencil_image; - GPUTexture *stencil_texture = BKE_image_get_gpu_texture(stencil_image, NULL, stencil_ibuf); - DRW_shgroup_uniform_texture(grp, "imgTexture", stencil_texture); - DRW_shgroup_uniform_bool_copy(grp, "imgPremultiplied", true); - DRW_shgroup_uniform_bool_copy(grp, "imgAlphaBlend", true); - DRW_shgroup_uniform_vec4_copy( - grp, "color", (float[4]){1.0f, 1.0f, 1.0f, brush->clone.alpha}); - - float size_image[2]; - BKE_image_get_size_fl(image, NULL, size_image); - float size_stencil_image[2] = {stencil_ibuf->x, stencil_ibuf->y}; - - float obmat[4][4]; - unit_m4(obmat); - obmat[3][1] = brush->clone.offset[1]; - obmat[3][0] = brush->clone.offset[0]; - obmat[0][0] = size_stencil_image[0] / size_image[0]; - obmat[1][1] = size_stencil_image[1] / size_image[1]; - - DRW_shgroup_call_obmat(grp, geom, obmat); - } - } - else { - pd->edit_uv.stencil_ibuf = NULL; - pd->edit_uv.stencil_image = NULL; - } - - if (pd->edit_uv.do_mask_overlay) { - const bool is_combined_overlay = pd->edit_uv.mask_overlay_mode == MASK_OVERLAY_COMBINED; - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS; - state |= is_combined_overlay ? DRW_STATE_BLEND_MUL : DRW_STATE_BLEND_ALPHA; - DRW_PASS_CREATE(psl->edit_uv_mask_ps, state); - - GPUShader *sh = OVERLAY_shader_edit_uv_mask_image(); - GPUBatch *geom = DRW_cache_quad_get(); - DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->edit_uv_mask_ps); - GPUTexture *mask_texture = edit_uv_mask_texture(pd->edit_uv.mask, - pd->edit_uv.image_size[0], - pd->edit_uv.image_size[1], - pd->edit_uv.image_aspect[1], - pd->edit_uv.image_aspect[1]); - pd->edit_uv.mask_texture = mask_texture; - DRW_shgroup_uniform_texture(grp, "imgTexture", mask_texture); - DRW_shgroup_uniform_vec4_copy(grp, "color", (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); - DRW_shgroup_call_obmat(grp, geom, NULL); - } - - /* HACK: When editing objects that share the same mesh we should only draw the - * first one in the order that is used during uv editing. We can only trust that the first object - * has the correct batches with the correct selection state. See T83187. */ - if ((pd->edit_uv.do_uv_overlay || pd->edit_uv.do_uv_shadow_overlay) && - draw_ctx->obact->type == OB_MESH) { - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data( - draw_ctx->scene, draw_ctx->view_layer, NULL, &objects_len, draw_ctx->object_mode); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *object_eval = DEG_get_evaluated_object(draw_ctx->depsgraph, objects[ob_index]); - DRW_mesh_batch_cache_validate(object_eval, (Mesh *)object_eval->data); - overlay_edit_uv_cache_populate(vedata, object_eval); - } - MEM_freeN(objects); - } -} - -static void overlay_edit_uv_cache_populate(OVERLAY_Data *vedata, Object *ob) -{ - if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { - return; - } - - OVERLAY_StorageList *stl = vedata->stl; - OVERLAY_PrivateData *pd = stl->pd; - GPUBatch *geom; - - const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool is_edit_object = DRW_object_is_in_edit_mode(ob); - Mesh *me = (Mesh *)ob->data; - const bool has_active_object_uvmap = CustomData_get_active_layer(&me->ldata, CD_MLOOPUV) != -1; - const bool has_active_edit_uvmap = is_edit_object && - (CustomData_get_active_layer(&me->edit_mesh->bm->ldata, - CD_MLOOPUV) != -1); - const bool draw_shadows = (draw_ctx->object_mode != OB_MODE_OBJECT) && - (ob->mode == draw_ctx->object_mode); - - if (has_active_edit_uvmap) { - if (pd->edit_uv.do_uv_overlay) { - geom = DRW_mesh_batch_cache_get_edituv_edges(ob, ob->data); - if (geom) { - DRW_shgroup_call_obmat(pd->edit_uv_edges_grp, geom, NULL); - } - if (pd->edit_uv.do_verts) { - geom = DRW_mesh_batch_cache_get_edituv_verts(ob, ob->data); - if (geom) { - DRW_shgroup_call_obmat(pd->edit_uv_verts_grp, geom, NULL); - } - } - if (pd->edit_uv.do_faces) { - geom = DRW_mesh_batch_cache_get_edituv_faces(ob, ob->data); - if (geom) { - DRW_shgroup_call_obmat(pd->edit_uv_faces_grp, geom, NULL); - } - } - if (pd->edit_uv.do_face_dots) { - geom = DRW_mesh_batch_cache_get_edituv_facedots(ob, ob->data); - if (geom) { - DRW_shgroup_call_obmat(pd->edit_uv_face_dots_grp, geom, NULL); - } - } - } - - if (pd->edit_uv.do_uv_stretching_overlay) { - if (pd->edit_uv.draw_type == SI_UVDT_STRETCH_ANGLE) { - geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(ob, me); - } - else /* SI_UVDT_STRETCH_AREA */ { - OVERLAY_StretchingAreaTotals *totals = MEM_mallocN(sizeof(OVERLAY_StretchingAreaTotals), - __func__); - BLI_addtail(&pd->edit_uv.totals, totals); - geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_area( - ob, me, &totals->total_area, &totals->total_area_uv); - } - if (geom) { - DRW_shgroup_call_obmat(pd->edit_uv_stretching_grp, geom, NULL); - } - } - } - - if (draw_shadows && (has_active_object_uvmap || has_active_edit_uvmap)) { - if (pd->edit_uv.do_uv_shadow_overlay) { - geom = DRW_mesh_batch_cache_get_uv_edges(ob, ob->data); - if (geom) { - DRW_shgroup_call_obmat(pd->edit_uv_shadow_edges_grp, geom, NULL); - } - } - } -} - -static void edit_uv_stretching_update_ratios(OVERLAY_Data *vedata) -{ - OVERLAY_StorageList *stl = vedata->stl; - OVERLAY_PrivateData *pd = stl->pd; - - if (pd->edit_uv.draw_type == SI_UVDT_STRETCH_AREA) { - float total_area = 0.0f; - float total_area_uv = 0.0f; - - LISTBASE_FOREACH (OVERLAY_StretchingAreaTotals *, totals, &pd->edit_uv.totals) { - total_area += *totals->total_area; - total_area_uv += *totals->total_area_uv; - } - - if (total_area > FLT_EPSILON && total_area_uv > FLT_EPSILON) { - pd->edit_uv.total_area_ratio = total_area / total_area_uv; - } - } - BLI_freelistN(&pd->edit_uv.totals); -} - -void OVERLAY_edit_uv_cache_finish(OVERLAY_Data *vedata) -{ - OVERLAY_StorageList *stl = vedata->stl; - OVERLAY_PrivateData *pd = stl->pd; - - if (pd->edit_uv.do_uv_stretching_overlay) { - edit_uv_stretching_update_ratios(vedata); - } -} - -static void OVERLAY_edit_uv_draw_finish(OVERLAY_Data *vedata) -{ - OVERLAY_StorageList *stl = vedata->stl; - OVERLAY_PrivateData *pd = stl->pd; - - if (pd->edit_uv.stencil_ibuf) { - BKE_image_release_ibuf( - pd->edit_uv.stencil_image, pd->edit_uv.stencil_ibuf, pd->edit_uv.stencil_lock); - pd->edit_uv.stencil_image = NULL; - pd->edit_uv.stencil_ibuf = NULL; - } - - DRW_TEXTURE_FREE_SAFE(pd->edit_uv.mask_texture); -} - -void OVERLAY_edit_uv_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_StorageList *stl = vedata->stl; - OVERLAY_PrivateData *pd = stl->pd; - - if (pd->edit_uv.do_tiled_image_border_overlay) { - DRW_draw_pass(psl->edit_uv_tiled_image_borders_ps); - } - if (pd->edit_uv.do_mask_overlay) { - /* Combined overlay renders in the default framebuffer and modifies the image in SRS. - * The alpha overlay renders in the overlay framebuffer. */ - const bool is_combined_overlay = pd->edit_uv.mask_overlay_mode == MASK_OVERLAY_COMBINED; - GPUFrameBuffer *previous_framebuffer = NULL; - if (is_combined_overlay) { - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - previous_framebuffer = GPU_framebuffer_active_get(); - GPU_framebuffer_bind(dfbl->default_fb); - } - DRW_draw_pass(psl->edit_uv_mask_ps); - if (previous_framebuffer) { - GPU_framebuffer_bind(previous_framebuffer); - } - } - - if (pd->edit_uv.do_uv_stretching_overlay) { - DRW_draw_pass(psl->edit_uv_stretching_ps); - } - - if (pd->edit_uv.do_uv_overlay) { - if (pd->edit_uv.do_faces) { - DRW_draw_pass(psl->edit_uv_faces_ps); - } - DRW_draw_pass(psl->edit_uv_edges_ps); - - DRW_draw_pass(psl->edit_uv_verts_ps); - } - else if (pd->edit_uv.do_uv_shadow_overlay) { - DRW_draw_pass(psl->edit_uv_edges_ps); - } - if (pd->edit_uv.do_stencil_overlay) { - DRW_draw_pass(psl->edit_uv_stencil_ps); - } - OVERLAY_edit_uv_draw_finish(vedata); -} - -/** \} */ diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.cc b/source/blender/draw/engines/overlay/overlay_edit_uv.cc new file mode 100644 index 00000000000..c173201b271 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_edit_uv.cc @@ -0,0 +1,596 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ +#include "DRW_render.h" + +#include "draw_cache_impl.h" +#include "draw_manager_text.h" + +#include "BKE_customdata.h" +#include "BKE_editmesh.h" +#include "BKE_image.h" +#include "BKE_layer.h" +#include "BKE_mask.h" +#include "BKE_object.h" +#include "BKE_paint.h" + +#include "DNA_brush_types.h" +#include "DNA_mesh_types.h" + +#include "DEG_depsgraph_query.h" + +#include "ED_image.h" + +#include "IMB_imbuf_types.h" + +#include "GPU_batch.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "overlay_private.hh" + +/* Forward declarations. */ +static void overlay_edit_uv_cache_populate(OVERLAY_Data *vedata, Object *ob); + +typedef struct OVERLAY_StretchingAreaTotals { + void *next, *prev; + float *total_area; + float *total_area_uv; +} OVERLAY_StretchingAreaTotals; + +static OVERLAY_UVLineStyle edit_uv_line_style_from_space_image(const SpaceImage *sima) +{ + const bool is_uv_editor = sima->mode == SI_MODE_UV; + if (is_uv_editor) { + switch (sima->dt_uv) { + case SI_UVDT_OUTLINE: + return OVERLAY_UV_LINE_STYLE_OUTLINE; + case SI_UVDT_BLACK: + return OVERLAY_UV_LINE_STYLE_BLACK; + case SI_UVDT_WHITE: + return OVERLAY_UV_LINE_STYLE_WHITE; + case SI_UVDT_DASH: + return OVERLAY_UV_LINE_STYLE_DASH; + default: + return OVERLAY_UV_LINE_STYLE_BLACK; + } + } + else { + return OVERLAY_UV_LINE_STYLE_SHADOW; + } +} + +/* TODO(jbakker): the GPU texture should be cached with the mask. */ +static GPUTexture *edit_uv_mask_texture( + Mask *mask, const int width, const int height_, const float aspx, const float aspy) +{ + const int height = (float)height_ * (aspy / aspx); + MaskRasterHandle *handle; + float *buffer = static_cast(MEM_mallocN(sizeof(float) * height * width, __func__)); + + /* Initialize rasterization handle. */ + handle = BKE_maskrasterize_handle_new(); + BKE_maskrasterize_handle_init(handle, mask, width, height, true, true, true); + + BKE_maskrasterize_buffer(handle, width, height, buffer); + + /* Free memory. */ + BKE_maskrasterize_handle_free(handle); + GPUTexture *texture = GPU_texture_create_2d(mask->id.name, width, height, 1, GPU_R16F, buffer); + MEM_freeN(buffer); + return texture; +} + +/* -------------------------------------------------------------------- */ +/** \name Internal API + * \{ */ + +void OVERLAY_edit_uv_init(OVERLAY_Data *vedata) +{ + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PrivateData *pd = stl->pd; + const DRWContextState *draw_ctx = DRW_context_state_get(); + SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; + const Scene *scene = draw_ctx->scene; + ToolSettings *ts = scene->toolsettings; + const Brush *brush = BKE_paint_brush(&ts->imapaint.paint); + const bool show_overlays = !pd->hide_overlays; + + Image *image = sima->image; + /* By design no image is an image type. This so editor shows UV's by default. */ + const bool is_image_type = (image == nullptr) || ELEM(image->type, + IMA_TYPE_IMAGE, + IMA_TYPE_MULTILAYER, + IMA_TYPE_UV_TEST); + const bool is_uv_editor = sima->mode == SI_MODE_UV; + const bool has_edit_object = (draw_ctx->object_edit) != nullptr; + const bool is_paint_mode = sima->mode == SI_MODE_PAINT; + const bool is_view_mode = sima->mode == SI_MODE_VIEW; + const bool is_mask_mode = sima->mode == SI_MODE_MASK; + const bool is_edit_mode = draw_ctx->object_mode == OB_MODE_EDIT; + const bool do_uv_overlay = is_image_type && is_uv_editor && has_edit_object; + const bool show_modified_uvs = sima->flag & SI_DRAWSHADOW; + const bool is_tiled_image = image && (image->source == IMA_SRC_TILED); + const bool do_edges_only = (ts->uv_flag & UV_SYNC_SELECTION) ? + /* NOTE: Ignore #SCE_SELECT_EDGE because a single selected edge + * on the mesh may cause single UV vertices to be selected. */ + false : + (ts->uv_selectmode == UV_SELECT_EDGE); + const bool do_faces = ((sima->flag & SI_NO_DRAWFACES) == 0); + const bool do_face_dots = (ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode & SCE_SELECT_FACE) != 0 : + (ts->uv_selectmode == UV_SELECT_FACE); + const bool do_uvstretching_overlay = is_image_type && is_uv_editor && is_edit_mode && + ((sima->flag & SI_DRAW_STRETCH) != 0); + const bool do_tex_paint_shadows = (sima->flag & SI_NO_DRAW_TEXPAINT) == 0; + const bool do_stencil_overlay = is_paint_mode && is_image_type && brush && + (brush->imagepaint_tool == PAINT_TOOL_CLONE) && + brush->clone.image; + + pd->edit_uv.do_verts = show_overlays && (!do_edges_only); + pd->edit_uv.do_faces = show_overlays && do_faces && !do_uvstretching_overlay; + pd->edit_uv.do_face_dots = show_overlays && do_faces && do_face_dots; + pd->edit_uv.do_uv_overlay = show_overlays && do_uv_overlay; + pd->edit_uv.do_uv_shadow_overlay = show_overlays && is_image_type && + ((is_paint_mode && do_tex_paint_shadows && + ((draw_ctx->object_mode & + (OB_MODE_TEXTURE_PAINT | OB_MODE_EDIT)) != 0)) || + (is_view_mode && do_tex_paint_shadows && + ((draw_ctx->object_mode & (OB_MODE_TEXTURE_PAINT)) != 0)) || + (do_uv_overlay && (show_modified_uvs))); + + pd->edit_uv.do_mask_overlay = show_overlays && is_mask_mode && + (sima->mask_info.mask != nullptr) && + ((sima->mask_info.draw_flag & MASK_DRAWFLAG_OVERLAY) != 0); + pd->edit_uv.mask_overlay_mode = eMaskOverlayMode(sima->mask_info.overlay_mode); + pd->edit_uv.mask = sima->mask_info.mask ? (Mask *)DEG_get_evaluated_id( + draw_ctx->depsgraph, &sima->mask_info.mask->id) : + nullptr; + + pd->edit_uv.do_uv_stretching_overlay = show_overlays && do_uvstretching_overlay; + pd->edit_uv.uv_opacity = sima->uv_opacity; + pd->edit_uv.do_tiled_image_overlay = show_overlays && is_image_type && is_tiled_image; + pd->edit_uv.do_tiled_image_border_overlay = is_image_type && is_tiled_image; + pd->edit_uv.dash_length = 4.0f * UI_DPI_FAC; + pd->edit_uv.line_style = edit_uv_line_style_from_space_image(sima); + pd->edit_uv.do_smooth_wire = ((U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) != 0); + pd->edit_uv.do_stencil_overlay = show_overlays && do_stencil_overlay; + + pd->edit_uv.draw_type = eSpaceImage_UVDT_Stretch(sima->dt_uvstretch); + BLI_listbase_clear(&pd->edit_uv.totals); + pd->edit_uv.total_area_ratio = 0.0f; + + /* During engine initialization phase the `sima` isn't locked and + * we are able to retrieve the needed data. + * During cache_init the image engine locks the `sima` and makes it impossible + * to retrieve the data. */ + ED_space_image_get_uv_aspect(sima, &pd->edit_uv.uv_aspect[0], &pd->edit_uv.uv_aspect[1]); + ED_space_image_get_size(sima, &pd->edit_uv.image_size[0], &pd->edit_uv.image_size[1]); + ED_space_image_get_aspect(sima, &pd->edit_uv.image_aspect[0], &pd->edit_uv.image_aspect[1]); +} + +void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = stl->pd; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; + Image *image = sima->image; + const Scene *scene = draw_ctx->scene; + ToolSettings *ts = scene->toolsettings; + + if (pd->edit_uv.do_uv_overlay || pd->edit_uv.do_uv_shadow_overlay) { + /* uv edges */ + { + DRW_PASS_CREATE(psl->edit_uv_edges_ps, + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | + DRW_STATE_BLEND_ALPHA); + const bool do_edges_only = (ts->uv_flag & UV_SYNC_SELECTION) ? + false : + (ts->uv_selectmode & UV_SELECT_EDGE); + GPUShader *sh = do_edges_only ? OVERLAY_shader_edit_uv_edges_for_edge_select_get() : + OVERLAY_shader_edit_uv_edges_get(); + if (pd->edit_uv.do_uv_shadow_overlay) { + pd->edit_uv_shadow_edges_grp = DRW_shgroup_create(sh, psl->edit_uv_edges_ps); + DRW_shgroup_uniform_block(pd->edit_uv_shadow_edges_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_int_copy( + pd->edit_uv_shadow_edges_grp, "lineStyle", OVERLAY_UV_LINE_STYLE_SHADOW); + DRW_shgroup_uniform_float_copy( + pd->edit_uv_shadow_edges_grp, "alpha", pd->edit_uv.uv_opacity); + DRW_shgroup_uniform_float( + pd->edit_uv_shadow_edges_grp, "dashLength", &pd->edit_uv.dash_length, 1); + DRW_shgroup_uniform_bool( + pd->edit_uv_shadow_edges_grp, "doSmoothWire", &pd->edit_uv.do_smooth_wire, 1); + } + + if (pd->edit_uv.do_uv_overlay) { + pd->edit_uv_edges_grp = DRW_shgroup_create(sh, psl->edit_uv_edges_ps); + DRW_shgroup_uniform_block(pd->edit_uv_edges_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_int_copy(pd->edit_uv_edges_grp, "lineStyle", pd->edit_uv.line_style); + DRW_shgroup_uniform_float_copy(pd->edit_uv_edges_grp, "alpha", pd->edit_uv.uv_opacity); + DRW_shgroup_uniform_float( + pd->edit_uv_edges_grp, "dashLength", &pd->edit_uv.dash_length, 1); + DRW_shgroup_uniform_bool( + pd->edit_uv_edges_grp, "doSmoothWire", &pd->edit_uv.do_smooth_wire, 1); + } + } + } + + if (pd->edit_uv.do_uv_overlay) { + if (pd->edit_uv.do_verts || pd->edit_uv.do_face_dots) { + DRW_PASS_CREATE(psl->edit_uv_verts_ps, + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | + DRW_STATE_BLEND_ALPHA); + } + + /* uv verts */ + if (pd->edit_uv.do_verts) { + GPUShader *sh = OVERLAY_shader_edit_uv_verts_get(); + pd->edit_uv_verts_grp = DRW_shgroup_create(sh, psl->edit_uv_verts_ps); + + const float point_size = UI_GetThemeValuef(TH_VERTEX_SIZE) * U.dpi_fac; + + DRW_shgroup_uniform_block(pd->edit_uv_verts_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy( + pd->edit_uv_verts_grp, "pointSize", (point_size + 1.5f) * M_SQRT2); + DRW_shgroup_uniform_float_copy(pd->edit_uv_verts_grp, "outlineWidth", 0.75f); + float theme_color[4]; + UI_GetThemeColor4fv(TH_VERTEX, theme_color); + srgb_to_linearrgb_v4(theme_color, theme_color); + DRW_shgroup_uniform_vec4_copy(pd->edit_uv_verts_grp, "color", theme_color); + } + + /* uv faces */ + if (pd->edit_uv.do_faces) { + DRW_PASS_CREATE(psl->edit_uv_faces_ps, + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA); + GPUShader *sh = OVERLAY_shader_edit_uv_face_get(); + pd->edit_uv_faces_grp = DRW_shgroup_create(sh, psl->edit_uv_faces_ps); + DRW_shgroup_uniform_block(pd->edit_uv_faces_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float(pd->edit_uv_faces_grp, "uvOpacity", &pd->edit_uv.uv_opacity, 1); + } + + /* uv face dots */ + if (pd->edit_uv.do_face_dots) { + const float point_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) * U.dpi_fac; + GPUShader *sh = OVERLAY_shader_edit_uv_face_dots_get(); + pd->edit_uv_face_dots_grp = DRW_shgroup_create(sh, psl->edit_uv_verts_ps); + DRW_shgroup_uniform_block(pd->edit_uv_face_dots_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(pd->edit_uv_face_dots_grp, "pointSize", point_size); + } + } + + /* uv stretching */ + if (pd->edit_uv.do_uv_stretching_overlay) { + DRW_PASS_CREATE(psl->edit_uv_stretching_ps, + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA); + if (pd->edit_uv.draw_type == SI_UVDT_STRETCH_ANGLE) { + GPUShader *sh = OVERLAY_shader_edit_uv_stretching_angle_get(); + pd->edit_uv_stretching_grp = DRW_shgroup_create(sh, psl->edit_uv_stretching_ps); + DRW_shgroup_uniform_block(pd->edit_uv_stretching_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_vec2_copy(pd->edit_uv_stretching_grp, "aspect", pd->edit_uv.uv_aspect); + } + else /* SI_UVDT_STRETCH_AREA */ { + GPUShader *sh = OVERLAY_shader_edit_uv_stretching_area_get(); + pd->edit_uv_stretching_grp = DRW_shgroup_create(sh, psl->edit_uv_stretching_ps); + DRW_shgroup_uniform_block(pd->edit_uv_stretching_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float( + pd->edit_uv_stretching_grp, "totalAreaRatio", &pd->edit_uv.total_area_ratio, 1); + } + } + + if (pd->edit_uv.do_tiled_image_border_overlay) { + GPUBatch *geom = DRW_cache_quad_wires_get(); + float obmat[4][4]; + unit_m4(obmat); + + DRW_PASS_CREATE(psl->edit_uv_tiled_image_borders_ps, + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS); + GPUShader *sh = OVERLAY_shader_edit_uv_tiled_image_borders_get(); + + float theme_color[4], selected_color[4]; + UI_GetThemeColorShade4fv(TH_BACK, 60, theme_color); + UI_GetThemeColor4fv(TH_FACE_SELECT, selected_color); + srgb_to_linearrgb_v4(theme_color, theme_color); + srgb_to_linearrgb_v4(selected_color, selected_color); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->edit_uv_tiled_image_borders_ps); + DRW_shgroup_uniform_vec4_copy(grp, "color", theme_color); + const float3 offset = {0.0f, 0.0f, 0.0f}; + DRW_shgroup_uniform_vec3_copy(grp, "offset", offset); + + LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { + const int tile_x = ((tile->tile_number - 1001) % 10); + const int tile_y = ((tile->tile_number - 1001) / 10); + obmat[3][1] = (float)tile_y; + obmat[3][0] = (float)tile_x; + DRW_shgroup_call_obmat(grp, geom, obmat); + } + /* Only mark active border when overlays are enabled. */ + if (pd->edit_uv.do_tiled_image_overlay) { + /* Active tile border */ + ImageTile *active_tile = static_cast( + BLI_findlink(&image->tiles, image->active_tile_index)); + if (active_tile) { + obmat[3][0] = (float)((active_tile->tile_number - 1001) % 10); + obmat[3][1] = (float)((active_tile->tile_number - 1001) / 10); + grp = DRW_shgroup_create(sh, psl->edit_uv_tiled_image_borders_ps); + DRW_shgroup_uniform_vec4_copy(grp, "color", selected_color); + DRW_shgroup_call_obmat(grp, geom, obmat); + } + } + } + + if (pd->edit_uv.do_tiled_image_overlay) { + struct DRWTextStore *dt = DRW_text_cache_ensure(); + uchar color[4]; + /* Color Management: Exception here as texts are drawn in sRGB space directly. */ + UI_GetThemeColorShade4ubv(TH_BACK, 60, color); + char text[16]; + LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { + BLI_snprintf(text, 5, "%d", tile->tile_number); + float tile_location[3] = {static_cast((tile->tile_number - 1001) % 10), + static_cast((tile->tile_number - 1001) / 10), + 0.0f}; + DRW_text_cache_add( + dt, tile_location, text, strlen(text), 10, 10, DRW_TEXT_CACHE_GLOBALSPACE, color); + } + } + + if (pd->edit_uv.do_stencil_overlay) { + const Brush *brush = BKE_paint_brush(&ts->imapaint.paint); + Image *stencil_image = brush->clone.image; + ImBuf *stencil_ibuf = BKE_image_acquire_ibuf( + stencil_image, nullptr, &pd->edit_uv.stencil_lock); + + if (stencil_ibuf == nullptr) { + pd->edit_uv.stencil_ibuf = nullptr; + pd->edit_uv.stencil_image = nullptr; + } + else { + DRW_PASS_CREATE(psl->edit_uv_stencil_ps, + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | + DRW_STATE_BLEND_ALPHA_PREMUL); + GPUShader *sh = OVERLAY_shader_edit_uv_stencil_image(); + GPUBatch *geom = DRW_cache_quad_get(); + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->edit_uv_stencil_ps); + pd->edit_uv.stencil_ibuf = stencil_ibuf; + pd->edit_uv.stencil_image = stencil_image; + GPUTexture *stencil_texture = BKE_image_get_gpu_texture( + stencil_image, nullptr, stencil_ibuf); + DRW_shgroup_uniform_texture(grp, "imgTexture", stencil_texture); + DRW_shgroup_uniform_bool_copy(grp, "imgPremultiplied", true); + DRW_shgroup_uniform_bool_copy(grp, "imgAlphaBlend", true); + const float4 color = {1.0f, 1.0f, 1.0f, brush->clone.alpha}; + DRW_shgroup_uniform_vec4_copy(grp, "color", color); + + float size_image[2]; + BKE_image_get_size_fl(image, nullptr, size_image); + float size_stencil_image[2] = {static_cast(stencil_ibuf->x), + static_cast(stencil_ibuf->y)}; + + float obmat[4][4]; + unit_m4(obmat); + obmat[3][1] = brush->clone.offset[1]; + obmat[3][0] = brush->clone.offset[0]; + obmat[0][0] = size_stencil_image[0] / size_image[0]; + obmat[1][1] = size_stencil_image[1] / size_image[1]; + + DRW_shgroup_call_obmat(grp, geom, obmat); + } + } + else { + pd->edit_uv.stencil_ibuf = nullptr; + pd->edit_uv.stencil_image = nullptr; + } + + if (pd->edit_uv.do_mask_overlay) { + const bool is_combined_overlay = pd->edit_uv.mask_overlay_mode == MASK_OVERLAY_COMBINED; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS; + state |= is_combined_overlay ? DRW_STATE_BLEND_MUL : DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->edit_uv_mask_ps, state); + + GPUShader *sh = OVERLAY_shader_edit_uv_mask_image(); + GPUBatch *geom = DRW_cache_quad_get(); + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->edit_uv_mask_ps); + GPUTexture *mask_texture = edit_uv_mask_texture(pd->edit_uv.mask, + pd->edit_uv.image_size[0], + pd->edit_uv.image_size[1], + pd->edit_uv.image_aspect[1], + pd->edit_uv.image_aspect[1]); + pd->edit_uv.mask_texture = mask_texture; + DRW_shgroup_uniform_texture(grp, "imgTexture", mask_texture); + const float4 color = {1.0f, 1.0f, 1.0f, 1.0f}; + DRW_shgroup_uniform_vec4_copy(grp, "color", color); + DRW_shgroup_call_obmat(grp, geom, nullptr); + } + + /* HACK: When editing objects that share the same mesh we should only draw the + * first one in the order that is used during uv editing. We can only trust that the first object + * has the correct batches with the correct selection state. See T83187. */ + if ((pd->edit_uv.do_uv_overlay || pd->edit_uv.do_uv_shadow_overlay) && + draw_ctx->obact->type == OB_MESH) { + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data( + draw_ctx->scene, draw_ctx->view_layer, nullptr, &objects_len, draw_ctx->object_mode); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *object_eval = DEG_get_evaluated_object(draw_ctx->depsgraph, objects[ob_index]); + DRW_mesh_batch_cache_validate(object_eval, (Mesh *)object_eval->data); + overlay_edit_uv_cache_populate(vedata, object_eval); + } + MEM_freeN(objects); + } +} + +static void overlay_edit_uv_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { + return; + } + + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PrivateData *pd = stl->pd; + GPUBatch *geom; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + const bool is_edit_object = DRW_object_is_in_edit_mode(ob); + Mesh *me = (Mesh *)ob->data; + const bool has_active_object_uvmap = CustomData_get_active_layer(&me->ldata, CD_MLOOPUV) != -1; + const bool has_active_edit_uvmap = is_edit_object && + (CustomData_get_active_layer(&me->edit_mesh->bm->ldata, + CD_MLOOPUV) != -1); + const bool draw_shadows = (draw_ctx->object_mode != OB_MODE_OBJECT) && + (ob->mode == draw_ctx->object_mode); + + if (has_active_edit_uvmap) { + if (pd->edit_uv.do_uv_overlay) { + geom = DRW_mesh_batch_cache_get_edituv_edges(ob, me); + if (geom) { + DRW_shgroup_call_obmat(pd->edit_uv_edges_grp, geom, nullptr); + } + if (pd->edit_uv.do_verts) { + geom = DRW_mesh_batch_cache_get_edituv_verts(ob, me); + if (geom) { + DRW_shgroup_call_obmat(pd->edit_uv_verts_grp, geom, nullptr); + } + } + if (pd->edit_uv.do_faces) { + geom = DRW_mesh_batch_cache_get_edituv_faces(ob, me); + if (geom) { + DRW_shgroup_call_obmat(pd->edit_uv_faces_grp, geom, nullptr); + } + } + if (pd->edit_uv.do_face_dots) { + geom = DRW_mesh_batch_cache_get_edituv_facedots(ob, me); + if (geom) { + DRW_shgroup_call_obmat(pd->edit_uv_face_dots_grp, geom, nullptr); + } + } + } + + if (pd->edit_uv.do_uv_stretching_overlay) { + if (pd->edit_uv.draw_type == SI_UVDT_STRETCH_ANGLE) { + geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(ob, me); + } + else /* SI_UVDT_STRETCH_AREA */ { + OVERLAY_StretchingAreaTotals *totals = static_cast( + MEM_mallocN(sizeof(OVERLAY_StretchingAreaTotals), __func__)); + BLI_addtail(&pd->edit_uv.totals, totals); + geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_area( + ob, me, &totals->total_area, &totals->total_area_uv); + } + if (geom) { + DRW_shgroup_call_obmat(pd->edit_uv_stretching_grp, geom, nullptr); + } + } + } + + if (draw_shadows && (has_active_object_uvmap || has_active_edit_uvmap)) { + if (pd->edit_uv.do_uv_shadow_overlay) { + geom = DRW_mesh_batch_cache_get_uv_edges(ob, me); + if (geom) { + DRW_shgroup_call_obmat(pd->edit_uv_shadow_edges_grp, geom, nullptr); + } + } + } +} + +static void edit_uv_stretching_update_ratios(OVERLAY_Data *vedata) +{ + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PrivateData *pd = stl->pd; + + if (pd->edit_uv.draw_type == SI_UVDT_STRETCH_AREA) { + float total_area = 0.0f; + float total_area_uv = 0.0f; + + LISTBASE_FOREACH (OVERLAY_StretchingAreaTotals *, totals, &pd->edit_uv.totals) { + total_area += *totals->total_area; + total_area_uv += *totals->total_area_uv; + } + + if (total_area > FLT_EPSILON && total_area_uv > FLT_EPSILON) { + pd->edit_uv.total_area_ratio = total_area / total_area_uv; + } + } + BLI_freelistN(&pd->edit_uv.totals); +} + +void OVERLAY_edit_uv_cache_finish(OVERLAY_Data *vedata) +{ + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PrivateData *pd = stl->pd; + + if (pd->edit_uv.do_uv_stretching_overlay) { + edit_uv_stretching_update_ratios(vedata); + } +} + +static void OVERLAY_edit_uv_draw_finish(OVERLAY_Data *vedata) +{ + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PrivateData *pd = stl->pd; + + if (pd->edit_uv.stencil_ibuf) { + BKE_image_release_ibuf( + pd->edit_uv.stencil_image, pd->edit_uv.stencil_ibuf, pd->edit_uv.stencil_lock); + pd->edit_uv.stencil_image = nullptr; + pd->edit_uv.stencil_ibuf = nullptr; + } + + DRW_TEXTURE_FREE_SAFE(pd->edit_uv.mask_texture); +} + +void OVERLAY_edit_uv_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PrivateData *pd = stl->pd; + + if (pd->edit_uv.do_tiled_image_border_overlay) { + DRW_draw_pass(psl->edit_uv_tiled_image_borders_ps); + } + if (pd->edit_uv.do_mask_overlay) { + /* Combined overlay renders in the default framebuffer and modifies the image in SRS. + * The alpha overlay renders in the overlay framebuffer. */ + const bool is_combined_overlay = pd->edit_uv.mask_overlay_mode == MASK_OVERLAY_COMBINED; + GPUFrameBuffer *previous_framebuffer = nullptr; + if (is_combined_overlay) { + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + previous_framebuffer = GPU_framebuffer_active_get(); + GPU_framebuffer_bind(dfbl->default_fb); + } + DRW_draw_pass(psl->edit_uv_mask_ps); + if (previous_framebuffer) { + GPU_framebuffer_bind(previous_framebuffer); + } + } + + if (pd->edit_uv.do_uv_stretching_overlay) { + DRW_draw_pass(psl->edit_uv_stretching_ps); + } + + if (pd->edit_uv.do_uv_overlay) { + if (pd->edit_uv.do_faces) { + DRW_draw_pass(psl->edit_uv_faces_ps); + } + DRW_draw_pass(psl->edit_uv_edges_ps); + + DRW_draw_pass(psl->edit_uv_verts_ps); + } + else if (pd->edit_uv.do_uv_shadow_overlay) { + DRW_draw_pass(psl->edit_uv_edges_ps); + } + if (pd->edit_uv.do_stencil_overlay) { + DRW_draw_pass(psl->edit_uv_stencil_ps); + } + OVERLAY_edit_uv_draw_finish(vedata); +} + +/** \} */ diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c deleted file mode 100644 index 6e2da95e405..00000000000 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ /dev/null @@ -1,747 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * 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 "DEG_depsgraph_query.h" - -#include "ED_view3d.h" - -#include "UI_interface.h" - -#include "BKE_object.h" -#include "BKE_paint.h" - -#include "DNA_space_types.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; - const Scene *scene = draw_ctx->scene; - const ToolSettings *ts = scene->toolsettings; - - if (!stl->pd) { - /* Allocate transient pointers. */ - stl->pd = MEM_callocN(sizeof(*stl->pd), __func__); - } - - /* Allocate instance. */ - if (data->instance == NULL) { - data->instance = MEM_callocN(sizeof(*data->instance), __func__); - } - - OVERLAY_PrivateData *pd = stl->pd; - pd->space_type = v3d != NULL ? SPACE_VIEW3D : draw_ctx->space_data->spacetype; - - if (pd->space_type == SPACE_IMAGE) { - const SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; - pd->hide_overlays = (sima->overlay.flag & SI_OVERLAY_SHOW_OVERLAYS) == 0; - pd->clipping_state = 0; - OVERLAY_grid_init(data); - OVERLAY_edit_uv_init(data); - return; - } - if (pd->space_type == SPACE_NODE) { - pd->hide_overlays = true; - pd->clipping_state = 0; - return; - } - - 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) { - pd->overlay = v3d->overlay; - pd->v3d_flag = v3d->flag; - pd->v3d_gridflag = v3d->gridflag; - } - else { - memset(&pd->overlay, 0, sizeof(pd->overlay)); - pd->v3d_flag = 0; - pd->v3d_gridflag = 0; - pd->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; - pd->overlay.wireframe_threshold = v3d->overlay.wireframe_threshold; - pd->overlay.wireframe_opacity = v3d->overlay.wireframe_opacity; - } - - if (v3d->shading.type == OB_WIRE) { - pd->overlay.flag |= V3D_OVERLAY_WIREFRAMES; - } - - if (ts->sculpt) { - if (ts->sculpt->flags & SCULPT_HIDE_FACE_SETS) { - pd->overlay.sculpt_mode_face_sets_opacity = 0.0f; - } - if (ts->sculpt->flags & SCULPT_HIDE_MASK) { - pd->overlay.sculpt_mode_mask_opacity = 0.0f; - } - } - - pd->use_in_front = (v3d->shading.type <= OB_SOLID) || - BKE_scene_uses_blender_workbench(draw_ctx->scene); - pd->wireframe_mode = (v3d->shading.type == OB_WIRE); - pd->clipping_state = RV3D_CLIPPING_ENABLED(v3d, rv3d) ? DRW_STATE_CLIP_PLANES : 0; - pd->xray_opacity = XRAY_ALPHA(v3d); - 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); - pd->cfra = DEG_get_ctime(draw_ctx->depsgraph); - - OVERLAY_antialiasing_init(vedata); - - switch (stl->pd->ctx_mode) { - case CTX_MODE_EDIT_MESH: - OVERLAY_edit_mesh_init(vedata); - break; - case CTX_MODE_EDIT_CURVES: - OVERLAY_edit_curves_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); - OVERLAY_paint_init(vedata); -} - -static void OVERLAY_cache_init(void *vedata) -{ - OVERLAY_Data *data = vedata; - OVERLAY_StorageList *stl = data->stl; - OVERLAY_PrivateData *pd = stl->pd; - - if (pd->space_type == SPACE_IMAGE) { - OVERLAY_background_cache_init(vedata); - OVERLAY_grid_cache_init(vedata); - OVERLAY_edit_uv_cache_init(vedata); - return; - } - if (pd->space_type == SPACE_NODE) { - OVERLAY_background_cache_init(vedata); - return; - } - - switch (pd->ctx_mode) { - case CTX_MODE_EDIT_MESH: - OVERLAY_edit_mesh_cache_init(vedata); - /* `pd->edit_mesh.flag` is valid after calling `OVERLAY_edit_mesh_cache_init`. */ - const bool draw_edit_weights = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_WEIGHT); - if (draw_edit_weights) { - OVERLAY_paint_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_EDIT_GPENCIL: - case CTX_MODE_PAINT_GPENCIL: - case CTX_MODE_SCULPT_GPENCIL: - case CTX_MODE_VERTEX_GPENCIL: - case CTX_MODE_WEIGHT_GPENCIL: - OVERLAY_edit_gpencil_cache_init(vedata); - break; - case CTX_MODE_EDIT_CURVES: - OVERLAY_edit_curves_cache_init(vedata); - break; - case CTX_MODE_SCULPT_CURVES: - OVERLAY_sculpt_curves_cache_init(vedata); - break; - case CTX_MODE_OBJECT: - break; - default: - BLI_assert_msg(0, "Draw mode invalid"); - break; - } - OVERLAY_antialiasing_cache_init(vedata); - OVERLAY_armature_cache_init(vedata); - OVERLAY_background_cache_init(vedata); - OVERLAY_fade_cache_init(vedata); - OVERLAY_mode_transfer_cache_init(vedata); - OVERLAY_extra_cache_init(vedata); - OVERLAY_facing_cache_init(vedata); - OVERLAY_gpencil_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); - OVERLAY_volume_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_CURVES_LEGACY, 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, reinitialize. */ - *do_init = true; - } - return *dupli_data; - } - return NULL; -} - -static bool overlay_object_is_edit_mode(const OVERLAY_PrivateData *pd, const Object *ob) -{ - if (DRW_object_is_in_edit_mode(ob)) { - /* Also check for context mode as the object mode is not 100% reliable. (see T72490) */ - switch (ob->type) { - case OB_MESH: - return pd->ctx_mode == CTX_MODE_EDIT_MESH; - case OB_ARMATURE: - return pd->ctx_mode == CTX_MODE_EDIT_ARMATURE; - case OB_CURVES_LEGACY: - return pd->ctx_mode == CTX_MODE_EDIT_CURVE; - case OB_SURF: - return pd->ctx_mode == CTX_MODE_EDIT_SURFACE; - case OB_LATTICE: - return pd->ctx_mode == CTX_MODE_EDIT_LATTICE; - case OB_MBALL: - return pd->ctx_mode == CTX_MODE_EDIT_METABALL; - case OB_FONT: - return pd->ctx_mode == CTX_MODE_EDIT_TEXT; - case OB_CURVES: - return pd->ctx_mode == CTX_MODE_EDIT_CURVES; - case OB_POINTCLOUD: - case OB_VOLUME: - /* No edit mode yet. */ - return false; - } - } - return false; -} - -static bool overlay_should_fade_object(Object *ob, Object *active_object) -{ - if (!active_object || !ob) { - return false; - } - - if (ELEM(active_object->mode, OB_MODE_OBJECT, OB_MODE_POSE)) { - return false; - } - - if ((active_object->mode & ob->mode) != 0) { - return false; - } - - return true; -} - -static void OVERLAY_cache_populate(void *vedata, Object *ob) -{ - OVERLAY_Data *data = vedata; - OVERLAY_PrivateData *pd = data->stl->pd; - - if (pd->space_type == SPACE_IMAGE) { - return; - } - - 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 = overlay_object_is_edit_mode(pd, ob); - const bool is_instance = (ob->base_flag & BASE_FROM_DUPLI); - const bool instance_parent_in_edit_mode = is_instance ? - overlay_object_is_edit_mode( - pd, DRW_object_get_dupli_parent(ob)) : - false; - const bool in_particle_edit_mode = (ob->mode == OB_MODE_PARTICLE_EDIT) && - (pd->ctx_mode == CTX_MODE_PARTICLE); - const bool in_paint_mode = (ob == draw_ctx->obact) && - (draw_ctx->object_mode & OB_MODE_ALL_PAINT); - const bool in_sculpt_curve_mode = (ob == draw_ctx->obact) && - (draw_ctx->object_mode & OB_MODE_SCULPT_CURVES); - const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != NULL) && - (ob->sculpt->mode_type == OB_MODE_SCULPT); - const bool in_curves_sculpt_mode = (ob == draw_ctx->obact) && - (ob->mode == OB_MODE_SCULPT_CURVES); - const bool has_surface = ELEM(ob->type, - OB_MESH, - OB_CURVES_LEGACY, - OB_SURF, - OB_FONT, - OB_GPENCIL, - OB_CURVES, - OB_POINTCLOUD, - OB_VOLUME); - 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) && - !is_select; - const bool draw_fade = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FADE_INACTIVE) && - overlay_should_fade_object(ob, draw_ctx->obact); - const bool draw_mode_transfer = draw_surface; - 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 && !in_sculpt_curve_mode && - renderable && has_surface && !instance_parent_in_edit_mode && - (pd->v3d_flag & V3D_SELECT_OUTLINE) && - (ob->base_flag & BASE_SELECTED); - const bool draw_bone_selection = (ob->type == OB_MESH) && pd->armature.do_pose_fade_geom && - !is_select; - const bool draw_edit_weights = in_edit_mode && (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_WEIGHT); - const bool draw_extras = - (!pd->hide_overlays) && - (((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_fade) { - OVERLAY_fade_cache_populate(vedata, ob); - } - if (draw_facing) { - OVERLAY_facing_cache_populate(vedata, ob); - } - if (draw_mode_transfer) { - OVERLAY_mode_transfer_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 (ob->type == OB_VOLUME) { - OVERLAY_volume_cache_populate(vedata, ob); - } - - if (in_edit_mode && !pd->hide_overlays) { - switch (ob->type) { - case OB_MESH: - OVERLAY_edit_mesh_cache_populate(vedata, ob); - if (draw_edit_weights) { - OVERLAY_paint_weight_cache_populate(vedata, ob); - } - break; - case OB_ARMATURE: - if (draw_bones) { - OVERLAY_edit_armature_cache_populate(vedata, ob); - } - break; - case OB_CURVES_LEGACY: - 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; - case OB_CURVES: - OVERLAY_edit_curves_cache_populate(vedata, ob); - break; - } - } - else if (in_pose_mode && draw_bones) { - OVERLAY_pose_armature_cache_populate(vedata, ob); - } - else if (in_paint_mode && !pd->hide_overlays) { - 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); - } - else if (in_curves_sculpt_mode) { - OVERLAY_sculpt_curves_cache_populate(vedata, ob); - } - - if (draw_motion_paths) { - OVERLAY_motion_path_cache_populate(vedata, ob); - } - - if (!pd->hide_overlays) { - 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: { - /* Unlike the other types above, lattices actually have a bounding box defined, so hide the - * lattice wires if only the bounding-box is requested. */ - if (ob->dt > OB_BOUNDBOX) { - OVERLAY_lattice_cache_populate(vedata, ob); - } - break; - } - } - } - - if (!BLI_listbase_is_empty(&ob->particlesystem)) { - OVERLAY_particle_cache_populate(vedata, ob); - } - - /* Relationship, object center, bounding-box... etc. */ - if (!pd->hide_overlays) { - OVERLAY_extra_cache_populate(vedata, ob); - } - - if (dupli) { - dupli->base_flag = ob->base_flag; - } -} - -static void OVERLAY_cache_finish(void *vedata) -{ - OVERLAY_Data *data = vedata; - OVERLAY_PrivateData *pd = data->stl->pd; - - if (ELEM(pd->space_type, SPACE_IMAGE)) { - OVERLAY_edit_uv_cache_finish(vedata); - return; - } - if (ELEM(pd->space_type, SPACE_NODE)) { - return; - } - - /* TODO(fclem): Only do this when really needed. */ - { - /* HACK we allocate the in front 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->in_front_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); - } - - OVERLAY_mode_transfer_cache_finish(vedata); - 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; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - - /* Needs to be done first as it modifies the scene color and depth buffer. */ - if (pd->space_type == SPACE_VIEW3D) { - OVERLAY_image_scene_background_draw(vedata); - } - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(dfbl->overlay_only_fb); - /* Don't clear background for the node editor. The node editor draws the background and we - * need to mask out the image from the already drawn overlay color buffer. */ - if (pd->space_type != SPACE_NODE) { - const float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - GPU_framebuffer_clear_color(dfbl->overlay_only_fb, clear_col); - } - } - - if (pd->space_type == SPACE_IMAGE) { - OVERLAY_background_draw(data); - OVERLAY_grid_draw(data); - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(dfbl->overlay_fb); - } - OVERLAY_edit_uv_draw(data); - return; - } - if (pd->space_type == SPACE_NODE) { - OVERLAY_background_draw(data); - return; - } - - OVERLAY_image_background_draw(vedata); - OVERLAY_background_draw(vedata); - - OVERLAY_antialiasing_start(vedata); - - DRW_view_set_active(NULL); - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_color_only_fb); - } - - OVERLAY_outline_draw(vedata); - OVERLAY_xray_depth_copy(vedata); - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_default_fb); - } - - OVERLAY_image_draw(vedata); - OVERLAY_fade_draw(vedata); - OVERLAY_facing_draw(vedata); - OVERLAY_mode_transfer_draw(vedata); - OVERLAY_extra_blend_draw(vedata); - OVERLAY_volume_draw(vedata); - - /* These overlays are drawn here to avoid artifacts with wire-frame opacity. */ - switch (pd->ctx_mode) { - case CTX_MODE_SCULPT: - OVERLAY_sculpt_draw(vedata); - break; - case CTX_MODE_SCULPT_CURVES: - OVERLAY_sculpt_curves_draw(vedata); - break; - case CTX_MODE_EDIT_MESH: - case CTX_MODE_POSE: - case CTX_MODE_PAINT_WEIGHT: - case CTX_MODE_PAINT_VERTEX: - case CTX_MODE_PAINT_TEXTURE: - OVERLAY_paint_draw(vedata); - break; - default: - break; - } - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_line_fb); - } - - OVERLAY_wireframe_draw(vedata); - OVERLAY_armature_draw(vedata); - OVERLAY_particle_draw(vedata); - OVERLAY_metaball_draw(vedata); - OVERLAY_gpencil_draw(vedata); - OVERLAY_extra_draw(vedata); - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_color_only_fb); - } - - OVERLAY_xray_fade_draw(vedata); - OVERLAY_grid_draw(vedata); - - OVERLAY_xray_depth_infront_copy(vedata); - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_in_front_fb); - } - - OVERLAY_fade_infront_draw(vedata); - OVERLAY_facing_infront_draw(vedata); - OVERLAY_mode_transfer_infront_draw(vedata); - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_line_in_front_fb); - } - - OVERLAY_wireframe_in_front_draw(vedata); - OVERLAY_armature_in_front_draw(vedata); - OVERLAY_extra_in_front_draw(vedata); - OVERLAY_metaball_in_front_draw(vedata); - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_color_only_fb); - } - - OVERLAY_image_in_front_draw(vedata); - OVERLAY_motion_path_draw(vedata); - OVERLAY_extra_centers_draw(vedata); - - if (DRW_state_is_select() || DRW_state_is_depth()) { - /* Edit modes have their own selection code. */ - return; - } - - /* Functions after this point can change FBO freely. */ - - 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: - OVERLAY_edit_text_draw(vedata); - break; - case CTX_MODE_EDIT_LATTICE: - OVERLAY_edit_lattice_draw(vedata); - break; - case CTX_MODE_POSE: - OVERLAY_pose_draw(vedata); - break; - case CTX_MODE_PARTICLE: - OVERLAY_edit_particle_draw(vedata); - break; - case CTX_MODE_EDIT_GPENCIL: - case CTX_MODE_PAINT_GPENCIL: - case CTX_MODE_SCULPT_GPENCIL: - case CTX_MODE_VERTEX_GPENCIL: - case CTX_MODE_WEIGHT_GPENCIL: - OVERLAY_edit_gpencil_draw(vedata); - break; - case CTX_MODE_SCULPT_CURVES: - break; - case CTX_MODE_EDIT_CURVES: - OVERLAY_edit_curves_draw(vedata); - break; - default: - break; - } - - OVERLAY_antialiasing_end(vedata); -} - -static void OVERLAY_engine_free(void) -{ - OVERLAY_shader_free(); -} - -static void OVERLAY_instance_free(void *instance_) -{ - OVERLAY_Instance *instance = (OVERLAY_Instance *)instance_; - DRW_UBO_FREE_SAFE(instance->grid_ubo); - MEM_freeN(instance); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \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_instance_free, - &OVERLAY_cache_init, - &OVERLAY_cache_populate, - &OVERLAY_cache_finish, - &OVERLAY_draw_scene, - NULL, - NULL, - NULL, - NULL, -}; - -/** \} */ - -#undef SELECT_ENGINE diff --git a/source/blender/draw/engines/overlay/overlay_engine.cc b/source/blender/draw/engines/overlay/overlay_engine.cc new file mode 100644 index 00000000000..9ee7cc4a10c --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_engine.cc @@ -0,0 +1,751 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * 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 "DEG_depsgraph_query.h" + +#include "ED_view3d.h" + +#include "UI_interface.h" + +#include "BKE_object.h" +#include "BKE_paint.h" + +#include "DNA_space_types.h" + +#include "overlay_engine.h" +#include "overlay_private.hh" + +/* -------------------------------------------------------------------- */ +/** \name Engine Callbacks + * \{ */ + +static void OVERLAY_engine_init(void *vedata) +{ + OVERLAY_Data *data = static_cast(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; + const Scene *scene = draw_ctx->scene; + const ToolSettings *ts = scene->toolsettings; + + if (!stl->pd) { + /* Allocate transient pointers. */ + stl->pd = static_cast(MEM_callocN(sizeof(*stl->pd), __func__)); + } + + /* Allocate instance. */ + if (data->instance == nullptr) { + data->instance = static_cast( + MEM_callocN(sizeof(*data->instance), __func__)); + } + + OVERLAY_PrivateData *pd = stl->pd; + pd->space_type = v3d != nullptr ? SPACE_VIEW3D : draw_ctx->space_data->spacetype; + + if (pd->space_type == SPACE_IMAGE) { + const SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; + pd->hide_overlays = (sima->overlay.flag & SI_OVERLAY_SHOW_OVERLAYS) == 0; + pd->clipping_state = DRWState(0); + OVERLAY_grid_init(data); + OVERLAY_edit_uv_init(data); + return; + } + if (pd->space_type == SPACE_NODE) { + pd->hide_overlays = true; + pd->clipping_state = DRWState(0); + return; + } + + 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) { + pd->overlay = v3d->overlay; + pd->v3d_flag = v3d->flag; + pd->v3d_gridflag = v3d->gridflag; + } + else { + memset(&pd->overlay, 0, sizeof(pd->overlay)); + pd->v3d_flag = 0; + pd->v3d_gridflag = 0; + pd->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; + pd->overlay.wireframe_threshold = v3d->overlay.wireframe_threshold; + pd->overlay.wireframe_opacity = v3d->overlay.wireframe_opacity; + } + + if (v3d->shading.type == OB_WIRE) { + pd->overlay.flag |= V3D_OVERLAY_WIREFRAMES; + } + + if (ts->sculpt) { + if (ts->sculpt->flags & SCULPT_HIDE_FACE_SETS) { + pd->overlay.sculpt_mode_face_sets_opacity = 0.0f; + } + if (ts->sculpt->flags & SCULPT_HIDE_MASK) { + pd->overlay.sculpt_mode_mask_opacity = 0.0f; + } + } + + pd->use_in_front = (v3d->shading.type <= OB_SOLID) || + BKE_scene_uses_blender_workbench(draw_ctx->scene); + pd->wireframe_mode = (v3d->shading.type == OB_WIRE); + pd->clipping_state = RV3D_CLIPPING_ENABLED(v3d, rv3d) ? DRW_STATE_CLIP_PLANES : DRWState(0); + pd->xray_opacity = XRAY_ALPHA(v3d); + 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); + pd->cfra = DEG_get_ctime(draw_ctx->depsgraph); + + OVERLAY_antialiasing_init(data); + + switch (stl->pd->ctx_mode) { + case CTX_MODE_EDIT_MESH: + OVERLAY_edit_mesh_init(data); + break; + case CTX_MODE_EDIT_CURVES: + OVERLAY_edit_curves_init(data); + break; + default: + /* Nothing to do. */ + break; + } + OVERLAY_facing_init(data); + OVERLAY_grid_init(data); + OVERLAY_image_init(data); + OVERLAY_outline_init(data); + OVERLAY_wireframe_init(data); + OVERLAY_paint_init(data); +} + +static void OVERLAY_cache_init(void *vedata) +{ + OVERLAY_Data *data = static_cast(vedata); + OVERLAY_StorageList *stl = data->stl; + OVERLAY_PrivateData *pd = stl->pd; + + if (pd->space_type == SPACE_IMAGE) { + OVERLAY_background_cache_init(data); + OVERLAY_grid_cache_init(data); + OVERLAY_edit_uv_cache_init(data); + return; + } + if (pd->space_type == SPACE_NODE) { + OVERLAY_background_cache_init(data); + return; + } + + switch (pd->ctx_mode) { + case CTX_MODE_EDIT_MESH: { + OVERLAY_edit_mesh_cache_init(data); + /* `pd->edit_mesh.flag` is valid after calling `OVERLAY_edit_mesh_cache_init`. */ + const bool draw_edit_weights = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_WEIGHT); + if (draw_edit_weights) { + OVERLAY_paint_cache_init(data); + } + break; + } + case CTX_MODE_EDIT_SURFACE: + case CTX_MODE_EDIT_CURVE: + OVERLAY_edit_curve_cache_init(data); + break; + case CTX_MODE_EDIT_TEXT: + OVERLAY_edit_text_cache_init(data); + break; + case CTX_MODE_EDIT_ARMATURE: + break; + case CTX_MODE_EDIT_METABALL: + break; + case CTX_MODE_EDIT_LATTICE: + OVERLAY_edit_lattice_cache_init(data); + break; + case CTX_MODE_PARTICLE: + OVERLAY_edit_particle_cache_init(data); + break; + case CTX_MODE_POSE: + case CTX_MODE_PAINT_WEIGHT: + case CTX_MODE_PAINT_VERTEX: + case CTX_MODE_PAINT_TEXTURE: + OVERLAY_paint_cache_init(data); + break; + case CTX_MODE_SCULPT: + OVERLAY_sculpt_cache_init(data); + break; + case CTX_MODE_EDIT_GPENCIL: + case CTX_MODE_PAINT_GPENCIL: + case CTX_MODE_SCULPT_GPENCIL: + case CTX_MODE_VERTEX_GPENCIL: + case CTX_MODE_WEIGHT_GPENCIL: + OVERLAY_edit_gpencil_cache_init(data); + break; + case CTX_MODE_EDIT_CURVES: + OVERLAY_edit_curves_cache_init(data); + break; + case CTX_MODE_SCULPT_CURVES: + OVERLAY_sculpt_curves_cache_init(data); + break; + case CTX_MODE_OBJECT: + break; + default: + BLI_assert_msg(0, "Draw mode invalid"); + break; + } + OVERLAY_antialiasing_cache_init(data); + OVERLAY_armature_cache_init(data); + OVERLAY_background_cache_init(data); + OVERLAY_fade_cache_init(data); + OVERLAY_mode_transfer_cache_init(data); + OVERLAY_extra_cache_init(data); + OVERLAY_facing_cache_init(data); + OVERLAY_gpencil_cache_init(data); + OVERLAY_grid_cache_init(data); + OVERLAY_image_cache_init(data); + OVERLAY_metaball_cache_init(data); + OVERLAY_motion_path_cache_init(data); + OVERLAY_outline_cache_init(data); + OVERLAY_particle_cache_init(data); + OVERLAY_wireframe_cache_init(data); + OVERLAY_volume_cache_init(data); +} + +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_CURVES_LEGACY, OB_FONT)) { + return nullptr; + } + + if (dupli_data) { + if (*dupli_data == nullptr) { + *dupli_data = static_cast( + MEM_callocN(sizeof(OVERLAY_DupliData), __func__)); + *do_init = true; + } + else if ((*dupli_data)->base_flag != ob->base_flag) { + /* Select state might have change, reinitialize. */ + *do_init = true; + } + return *dupli_data; + } + return nullptr; +} + +static bool overlay_object_is_edit_mode(const OVERLAY_PrivateData *pd, const Object *ob) +{ + if (DRW_object_is_in_edit_mode(ob)) { + /* Also check for context mode as the object mode is not 100% reliable. (see T72490) */ + switch (ob->type) { + case OB_MESH: + return pd->ctx_mode == CTX_MODE_EDIT_MESH; + case OB_ARMATURE: + return pd->ctx_mode == CTX_MODE_EDIT_ARMATURE; + case OB_CURVES_LEGACY: + return pd->ctx_mode == CTX_MODE_EDIT_CURVE; + case OB_SURF: + return pd->ctx_mode == CTX_MODE_EDIT_SURFACE; + case OB_LATTICE: + return pd->ctx_mode == CTX_MODE_EDIT_LATTICE; + case OB_MBALL: + return pd->ctx_mode == CTX_MODE_EDIT_METABALL; + case OB_FONT: + return pd->ctx_mode == CTX_MODE_EDIT_TEXT; + case OB_CURVES: + return pd->ctx_mode == CTX_MODE_EDIT_CURVES; + case OB_POINTCLOUD: + case OB_VOLUME: + /* No edit mode yet. */ + return false; + } + } + return false; +} + +static bool overlay_should_fade_object(Object *ob, Object *active_object) +{ + if (!active_object || !ob) { + return false; + } + + if (ELEM(active_object->mode, OB_MODE_OBJECT, OB_MODE_POSE)) { + return false; + } + + if ((active_object->mode & ob->mode) != 0) { + return false; + } + + return true; +} + +static void OVERLAY_cache_populate(void *vedata, Object *ob) +{ + OVERLAY_Data *data = static_cast(vedata); + OVERLAY_PrivateData *pd = data->stl->pd; + + if (pd->space_type == SPACE_IMAGE) { + return; + } + + 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 = overlay_object_is_edit_mode(pd, ob); + const bool is_instance = (ob->base_flag & BASE_FROM_DUPLI); + const bool instance_parent_in_edit_mode = is_instance ? + overlay_object_is_edit_mode( + pd, DRW_object_get_dupli_parent(ob)) : + false; + const bool in_particle_edit_mode = (ob->mode == OB_MODE_PARTICLE_EDIT) && + (pd->ctx_mode == CTX_MODE_PARTICLE); + const bool in_paint_mode = (ob == draw_ctx->obact) && + (draw_ctx->object_mode & OB_MODE_ALL_PAINT); + const bool in_sculpt_curve_mode = (ob == draw_ctx->obact) && + (draw_ctx->object_mode & OB_MODE_SCULPT_CURVES); + const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != nullptr) && + (ob->sculpt->mode_type == OB_MODE_SCULPT); + const bool in_curves_sculpt_mode = (ob == draw_ctx->obact) && + (ob->mode == OB_MODE_SCULPT_CURVES); + const bool has_surface = ELEM(ob->type, + OB_MESH, + OB_CURVES_LEGACY, + OB_SURF, + OB_FONT, + OB_GPENCIL, + OB_CURVES, + OB_POINTCLOUD, + OB_VOLUME); + 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) && + !is_select; + const bool draw_fade = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FADE_INACTIVE) && + overlay_should_fade_object(ob, draw_ctx->obact); + const bool draw_mode_transfer = draw_surface; + 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 && !in_sculpt_curve_mode && + renderable && has_surface && !instance_parent_in_edit_mode && + (pd->v3d_flag & V3D_SELECT_OUTLINE) && + (ob->base_flag & BASE_SELECTED); + const bool draw_bone_selection = (ob->type == OB_MESH) && pd->armature.do_pose_fade_geom && + !is_select; + const bool draw_edit_weights = in_edit_mode && (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_WEIGHT); + const bool draw_extras = + (!pd->hide_overlays) && + (((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_fade) { + OVERLAY_fade_cache_populate(data, ob); + } + if (draw_facing) { + OVERLAY_facing_cache_populate(data, ob); + } + if (draw_mode_transfer) { + OVERLAY_mode_transfer_cache_populate(data, ob); + } + if (draw_wires) { + OVERLAY_wireframe_cache_populate(data, ob, dupli, do_init); + } + if (draw_outlines) { + OVERLAY_outline_cache_populate(data, ob, dupli, do_init); + } + if (draw_bone_selection) { + OVERLAY_pose_cache_populate(data, ob); + } + + if (ob->type == OB_VOLUME) { + OVERLAY_volume_cache_populate(data, ob); + } + + if (in_edit_mode && !pd->hide_overlays) { + switch (ob->type) { + case OB_MESH: + OVERLAY_edit_mesh_cache_populate(data, ob); + if (draw_edit_weights) { + OVERLAY_paint_weight_cache_populate(data, ob); + } + break; + case OB_ARMATURE: + if (draw_bones) { + OVERLAY_edit_armature_cache_populate(data, ob); + } + break; + case OB_CURVES_LEGACY: + OVERLAY_edit_curve_cache_populate(data, ob); + break; + case OB_SURF: + OVERLAY_edit_surf_cache_populate(data, ob); + break; + case OB_LATTICE: + OVERLAY_edit_lattice_cache_populate(data, ob); + break; + case OB_MBALL: + OVERLAY_edit_metaball_cache_populate(data, ob); + break; + case OB_FONT: + OVERLAY_edit_text_cache_populate(data, ob); + break; + case OB_CURVES: + OVERLAY_edit_curves_cache_populate(data, ob); + break; + } + } + else if (in_pose_mode && draw_bones) { + OVERLAY_pose_armature_cache_populate(data, ob); + } + else if (in_paint_mode && !pd->hide_overlays) { + switch (draw_ctx->object_mode) { + case OB_MODE_VERTEX_PAINT: + OVERLAY_paint_vertex_cache_populate(data, ob); + break; + case OB_MODE_WEIGHT_PAINT: + OVERLAY_paint_weight_cache_populate(data, ob); + break; + case OB_MODE_TEXTURE_PAINT: + OVERLAY_paint_texture_cache_populate(data, ob); + break; + default: + break; + } + } + else if (in_particle_edit_mode) { + OVERLAY_edit_particle_cache_populate(data, ob); + } + + if (in_sculpt_mode) { + OVERLAY_sculpt_cache_populate(data, ob); + } + else if (in_curves_sculpt_mode) { + OVERLAY_sculpt_curves_cache_populate(data, ob); + } + + if (draw_motion_paths) { + OVERLAY_motion_path_cache_populate(data, ob); + } + + if (!pd->hide_overlays) { + switch (ob->type) { + case OB_ARMATURE: + if (draw_bones && (is_select || (!in_edit_mode && !in_pose_mode))) { + OVERLAY_armature_cache_populate(data, ob); + } + break; + case OB_MBALL: + if (!in_edit_mode) { + OVERLAY_metaball_cache_populate(data, ob); + } + break; + case OB_GPENCIL: + OVERLAY_gpencil_cache_populate(data, ob); + break; + } + } + /* Non-Meshes */ + if (draw_extras) { + switch (ob->type) { + case OB_EMPTY: + OVERLAY_empty_cache_populate(data, ob); + break; + case OB_LAMP: + OVERLAY_light_cache_populate(data, ob); + break; + case OB_CAMERA: + OVERLAY_camera_cache_populate(data, ob); + break; + case OB_SPEAKER: + OVERLAY_speaker_cache_populate(data, ob); + break; + case OB_LIGHTPROBE: + OVERLAY_lightprobe_cache_populate(data, ob); + break; + case OB_LATTICE: { + /* Unlike the other types above, lattices actually have a bounding box defined, so hide the + * lattice wires if only the bounding-box is requested. */ + if (ob->dt > OB_BOUNDBOX) { + OVERLAY_lattice_cache_populate(data, ob); + } + break; + } + } + } + + if (!BLI_listbase_is_empty(&ob->particlesystem)) { + OVERLAY_particle_cache_populate(data, ob); + } + + /* Relationship, object center, bounding-box... etc. */ + if (!pd->hide_overlays) { + OVERLAY_extra_cache_populate(data, ob); + } + + if (dupli) { + dupli->base_flag = ob->base_flag; + } +} + +static void OVERLAY_cache_finish(void *vedata) +{ + OVERLAY_Data *data = static_cast(vedata); + OVERLAY_PrivateData *pd = data->stl->pd; + + if (ELEM(pd->space_type, SPACE_IMAGE)) { + OVERLAY_edit_uv_cache_finish(data); + return; + } + if (ELEM(pd->space_type, SPACE_NODE)) { + return; + } + + /* TODO(fclem): Only do this when really needed. */ + { + /* HACK we allocate the in front 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, DRWTextureFlag(0)); + + GPU_framebuffer_ensure_config( + &dfbl->in_front_fb, + {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); + } + + OVERLAY_mode_transfer_cache_finish(data); + OVERLAY_antialiasing_cache_finish(data); + OVERLAY_armature_cache_finish(data); + OVERLAY_image_cache_finish(data); +} + +static void OVERLAY_draw_scene(void *vedata) +{ + OVERLAY_Data *data = static_cast(vedata); + OVERLAY_PrivateData *pd = data->stl->pd; + OVERLAY_FramebufferList *fbl = data->fbl; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + + /* Needs to be done first as it modifies the scene color and depth buffer. */ + if (pd->space_type == SPACE_VIEW3D) { + OVERLAY_image_scene_background_draw(data); + } + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(dfbl->overlay_only_fb); + /* Don't clear background for the node editor. The node editor draws the background and we + * need to mask out the image from the already drawn overlay color buffer. */ + if (pd->space_type != SPACE_NODE) { + const float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_clear_color(dfbl->overlay_only_fb, clear_col); + } + } + + if (pd->space_type == SPACE_IMAGE) { + OVERLAY_background_draw(data); + OVERLAY_grid_draw(data); + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(dfbl->overlay_fb); + } + OVERLAY_edit_uv_draw(data); + return; + } + if (pd->space_type == SPACE_NODE) { + OVERLAY_background_draw(data); + return; + } + + OVERLAY_image_background_draw(data); + OVERLAY_background_draw(data); + + OVERLAY_antialiasing_start(data); + + DRW_view_set_active(nullptr); + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_color_only_fb); + } + + OVERLAY_outline_draw(data); + OVERLAY_xray_depth_copy(data); + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_default_fb); + } + + OVERLAY_image_draw(data); + OVERLAY_fade_draw(data); + OVERLAY_facing_draw(data); + OVERLAY_mode_transfer_draw(data); + OVERLAY_extra_blend_draw(data); + OVERLAY_volume_draw(data); + + /* These overlays are drawn here to avoid artifacts with wire-frame opacity. */ + switch (pd->ctx_mode) { + case CTX_MODE_SCULPT: + OVERLAY_sculpt_draw(data); + break; + case CTX_MODE_SCULPT_CURVES: + OVERLAY_sculpt_curves_draw(data); + break; + case CTX_MODE_EDIT_MESH: + case CTX_MODE_POSE: + case CTX_MODE_PAINT_WEIGHT: + case CTX_MODE_PAINT_VERTEX: + case CTX_MODE_PAINT_TEXTURE: + OVERLAY_paint_draw(data); + break; + default: + break; + } + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_line_fb); + } + + OVERLAY_wireframe_draw(data); + OVERLAY_armature_draw(data); + OVERLAY_particle_draw(data); + OVERLAY_metaball_draw(data); + OVERLAY_gpencil_draw(data); + OVERLAY_extra_draw(data); + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_color_only_fb); + } + + OVERLAY_xray_fade_draw(data); + OVERLAY_grid_draw(data); + + OVERLAY_xray_depth_infront_copy(data); + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_in_front_fb); + } + + OVERLAY_fade_infront_draw(data); + OVERLAY_facing_infront_draw(data); + OVERLAY_mode_transfer_infront_draw(data); + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_line_in_front_fb); + } + + OVERLAY_wireframe_in_front_draw(data); + OVERLAY_armature_in_front_draw(data); + OVERLAY_extra_in_front_draw(data); + OVERLAY_metaball_in_front_draw(data); + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_color_only_fb); + } + + OVERLAY_image_in_front_draw(data); + OVERLAY_motion_path_draw(data); + OVERLAY_extra_centers_draw(data); + + if (DRW_state_is_select() || DRW_state_is_depth()) { + /* Edit modes have their own selection code. */ + return; + } + + /* Functions after this point can change FBO freely. */ + + switch (pd->ctx_mode) { + case CTX_MODE_EDIT_MESH: + OVERLAY_edit_mesh_draw(data); + break; + case CTX_MODE_EDIT_SURFACE: + case CTX_MODE_EDIT_CURVE: + OVERLAY_edit_curve_draw(data); + break; + case CTX_MODE_EDIT_TEXT: + OVERLAY_edit_text_draw(data); + break; + case CTX_MODE_EDIT_LATTICE: + OVERLAY_edit_lattice_draw(data); + break; + case CTX_MODE_POSE: + OVERLAY_pose_draw(data); + break; + case CTX_MODE_PARTICLE: + OVERLAY_edit_particle_draw(data); + break; + case CTX_MODE_EDIT_GPENCIL: + case CTX_MODE_PAINT_GPENCIL: + case CTX_MODE_SCULPT_GPENCIL: + case CTX_MODE_VERTEX_GPENCIL: + case CTX_MODE_WEIGHT_GPENCIL: + OVERLAY_edit_gpencil_draw(data); + break; + case CTX_MODE_SCULPT_CURVES: + break; + case CTX_MODE_EDIT_CURVES: + OVERLAY_edit_curves_draw(data); + break; + default: + break; + } + + OVERLAY_antialiasing_end(data); +} + +static void OVERLAY_engine_free(void) +{ + OVERLAY_shader_free(); +} + +static void OVERLAY_instance_free(void *instance_) +{ + OVERLAY_Instance *instance = (OVERLAY_Instance *)instance_; + DRW_UBO_FREE_SAFE(instance->grid_ubo); + MEM_freeN(instance); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Engine Type + * \{ */ + +static const DrawEngineDataSize overlay_data_size = DRW_VIEWPORT_DATA_SIZE(OVERLAY_Data); + +DrawEngineType draw_engine_overlay_type = { + nullptr, + nullptr, + N_("Overlay"), + &overlay_data_size, + &OVERLAY_engine_init, + &OVERLAY_engine_free, + &OVERLAY_instance_free, + &OVERLAY_cache_init, + &OVERLAY_cache_populate, + &OVERLAY_cache_finish, + &OVERLAY_draw_scene, + nullptr, + nullptr, + nullptr, + nullptr, +}; + +/** \} */ + +#undef SELECT_ENGINE diff --git a/source/blender/draw/engines/overlay/overlay_engine.h b/source/blender/draw/engines/overlay/overlay_engine.h index 18ab7f1456e..a33ea17dc1e 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.h +++ b/source/blender/draw/engines/overlay/overlay_engine.h @@ -7,4 +7,12 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + extern DrawEngineType draw_engine_overlay_type; + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c deleted file mode 100644 index 5d80ab3d0ea..00000000000 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ /dev/null @@ -1,1621 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "DRW_render.h" - -#include "UI_resources.h" - -#include "BKE_anim_path.h" -#include "BKE_camera.h" -#include "BKE_constraint.h" -#include "BKE_curve.h" -#include "BKE_global.h" -#include "BKE_mball.h" -#include "BKE_mesh.h" -#include "BKE_modifier.h" -#include "BKE_movieclip.h" -#include "BKE_object.h" -#include "BKE_tracking.h" - -#include "BLI_listbase.h" - -#include "DNA_camera_types.h" -#include "DNA_constraint_types.h" -#include "DNA_curve_types.h" -#include "DNA_fluid_types.h" -#include "DNA_lightprobe_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meta_types.h" -#include "DNA_modifier_types.h" -#include "DNA_pointcache_types.h" -#include "DNA_rigidbody_types.h" - -#include "DEG_depsgraph_query.h" - -#include "ED_view3d.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_TextureList *txl = vedata->txl; - OVERLAY_PrivateData *pd = vedata->stl->pd; - const bool is_select = DRW_state_is_select(); - - DRWState state_blend = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; - DRW_PASS_CREATE(psl->extra_blend_ps, state_blend | pd->clipping_state); - DRW_PASS_CREATE(psl->extra_centers_ps, state_blend | pd->clipping_state); - - { - DRWState state = DRW_STATE_WRITE_COLOR; - - DRW_PASS_CREATE(psl->extra_grid_ps, state | pd->clipping_state); - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - DRWShadingGroup *grp; - struct GPUShader *sh = OVERLAY_shader_extra_grid(); - struct GPUTexture *tex = DRW_state_is_fbo() ? dtxl->depth : txl->dummy_depth_tx; - - pd->extra_grid_grp = grp = DRW_shgroup_create(sh, psl->extra_grid_ps); - DRW_shgroup_uniform_texture(grp, "depthBuffer", tex); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); - } - - 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(is_select); - - grp = DRW_shgroup_create(sh, extra_ps); - DRW_shgroup_uniform_block(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(DRW_LOD_LOW)); - 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_cube_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->solid_quad = BUF_INSTANCE(grp_sub, format, DRW_cache_quad_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(grp, "globalsBlock", G_draw.block_ubo); - - grp_sub = DRW_shgroup_create_sub(grp); - DRW_shgroup_state_enable(grp_sub, DRW_STATE_DEPTH_LESS_EQUAL | 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_DEPTH_LESS_EQUAL | 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(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, is_select); - - grp = DRW_shgroup_create(sh, extra_ps); - DRW_shgroup_uniform_block(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, is_select); - - cb->extra_wire = grp = DRW_shgroup_create(sh, extra_ps); - DRW_shgroup_uniform_block(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(grp, "globalsBlock", G_draw.block_ubo); - - /* Buffer access for drawing isolated points, matching `extra_lines`. */ - cb->extra_points = BUF_POINT(grp, formats->point_extra); - } - { - 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(grp, "globalsBlock", G_draw.block_ubo); - - grp_sub = DRW_shgroup_create_sub(grp); - DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.color_active); - 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.color_select); - 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.color_deselect); - 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.color_library_select); - 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.color_library); - cb->center_deselected_lib = BUF_POINT(grp_sub, format); - } - } -} - -void OVERLAY_extra_point(OVERLAY_ExtraCallBuffers *cb, const float point[3], const float color[4]) -{ - DRW_buffer_add_entry(cb->extra_points, point, color); -} - -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_DRAW_IN_FRONT) != 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]; - const float col[4] = {UNPACK3(color), 0.0f /* No stipples. */}; - pack_v4_in_mat4(draw_mat, mat, col); - 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, - const float *color, - char boundtype, - bool around_origin) -{ - float center[3], size[3], tmp[4][4], final_mat[4][4]; - - if (ob->type == OB_MBALL && !BKE_mball_is_basis(ob)) { - return; - } - - const BoundBox *bb = BKE_object_boundbox_get(ob); - BoundBox bb_local; - if (bb == NULL) { - const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f}; - BKE_boundbox_init_from_minmax(&bb_local, min, max); - bb = &bb_local; - } - - 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, const float *color) -{ - switch (ob->rigidbody_object->shape) { - case RB_SHAPE_BOX: - OVERLAY_bounds(cb, ob, color, OB_BOUND_BOX, true); - break; - case RB_SHAPE_SPHERE: - OVERLAY_bounds(cb, ob, color, OB_BOUND_SPHERE, true); - break; - case RB_SHAPE_CONE: - OVERLAY_bounds(cb, ob, color, OB_BOUND_CONE, true); - break; - case RB_SHAPE_CYLINDER: - OVERLAY_bounds(cb, ob, color, OB_BOUND_CYLINDER, true); - break; - case RB_SHAPE_CAPSULE: - OVERLAY_bounds(cb, ob, color, OB_BOUND_CAPSULE, true); - break; - } -} - -static void OVERLAY_texture_space(OVERLAY_ExtraCallBuffers *cb, Object *ob, const float *color) -{ - 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_LEGACY: { - 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; - } - case ID_CV: - case ID_PT: - case ID_VO: { - /* No user defined texture space support. */ - break; - } - default: - BLI_assert(0); - } - - float mat[4][4]; - - if (texcoloc != NULL && texcosize != NULL) { - size_to_mat4(mat, texcosize); - copy_v3_v3(mat[3], texcoloc); - } - else { - unit_m4(mat); - } - - mul_m4_m4m4(mat, ob->obmat, mat); - - 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_CURVES_LEGACY) ? 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->anim_path_accum_length) { - instdata.size_x = instdata.size_y = instdata.size_z = pd->f_strength; - float pos[4]; - BKE_where_on_path(ob, 0.0f, pos, NULL, 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); - - BKE_where_on_path(ob, 1.0f, pos, NULL, 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] = {UNPACK3(color_p), 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: clip_end has no meaning nowadays. - * In EEVEE, Only clip_sta is used shadow-mapping. - * Clip end is computed automatically based on light power. - * For now, always use the custom distance as clip_end. */ - instdata.clip_end = la->att_dist; - 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) { - /* Previous implementation was using the clipend distance as cone size. - * We cannot do this anymore so we use a fixed size of 10. (see T72871) */ - rescale_m4(instdata.mat, (float[3]){10.0f, 10.0f, 10.0f}); - /* 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()) { - const float color_inside[4] = {0.0f, 0.0f, 0.0f, 0.5f}; - const 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 Light-probe - * \{ */ - -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; - int theme_id = 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; - const bool show_data = (ob->base_flag & BASE_SELECTED) || DRW_state_is_select(); - - 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_cube, 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); - } - - /* Data dots */ - if (show_data) { - instdata.mat[0][3] = prb->grid_resolution_x; - instdata.mat[1][3] = prb->grid_resolution_y; - instdata.mat[2][3] = prb->grid_resolution_z; - /* Put theme id in matrix. */ - if (theme_id == TH_ACTIVE) { - instdata.mat[3][3] = 1.0; - } - else /* TH_SELECT */ { - instdata.mat[3][3] = 2.0; - } - - uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z; - DRWShadingGroup *grp = DRW_shgroup_create_sub(vedata->stl->pd->extra_grid_grp); - DRW_shgroup_uniform_mat4_copy(grp, "gridModelMatrix", instdata.mat); - DRW_shgroup_call_procedural_points(grp, NULL, cell_count); - } - break; - case LIGHTPROBE_TYPE_PLANAR: - DRW_buffer_add_entry(cb->probe_planar, color_p, &instdata); - - if (DRW_state_is_select() && (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA)) { - DRW_buffer_add_entry(cb->solid_quad, 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 *ob, const float color[4]) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool is_select = DRW_state_is_select(); - - 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; - - float bundle_color_custom[3]; - float *bundle_color_solid = G_draw.block.color_bundle_solid; - float *bundle_color_unselected = G_draw.block.color_wire; - uchar text_color_selected[4], text_color_unselected[4]; - /* Color Management: Exception here as texts are drawn in sRGB space directly. */ - UI_GetThemeColor4ubv(TH_SELECT, text_color_selected); - UI_GetThemeColor4ubv(TH_TEXT, text_color_unselected); - - float camera_mat[4][4]; - BKE_tracking_get_camera_object_matrix(ob, camera_mat); - - 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); - - float object_imat[4][4]; - invert_m4_m4(object_imat, object_mat); - - mul_m4_m4m4(tracking_object_mat, ob->obmat, object_imat); - } - - ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object); - LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) { - 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) { - /* Meh, hardcoded srgb transform here. */ - /* TODO: change the actual DNA color to be linear. */ - srgb_to_linearrgb_v3_v3(bundle_color_custom, track->color); - bundle_color = bundle_color_custom; - } - 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(ob->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; - } - - 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; - - if (!is_stereo3d_cameras) { - /* Draw single camera. */ - DRW_buffer_add_entry_struct(cb->camera_frame, instdata); - } - - 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.color_wire); - } - - 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])); - /* Avoid division by 0. */ - if (ELEM(0.0f, scale[0], scale[1], scale[2])) { - return; - } - 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 positioning / 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, 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.color_wire; - float *constraint_color = G_draw.block.color_grid_axis_z; /* ? */ - - 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); - } - - /* Drawing the hook lines. */ - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Hook) { - HookModifierData *hmd = (HookModifierData *)md; - float center[3]; - mul_v3_m4v3(center, ob->obmat, hmd->cent); - if (hmd->object) { - OVERLAY_extra_line_dashed(cb, hmd->object->obmat[3], center, relation_color); - } - OVERLAY_extra_point(cb, center, 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); - ListBase targets = {NULL, NULL}; - - if ((curcon->ui_expand_flag & (1 << 0)) && BKE_constraint_targets_get(curcon, &targets)) { - bConstraintTarget *ct; - - BKE_constraint_custom_object_space_init(cob, curcon); - - for (ct = targets.first; ct; ct = ct->next) { - /* calculate target's matrix */ - if (ct->flag & CONSTRAINT_TAR_CUSTOM_SPACE) { - copy_m4_m4(ct->matrix, cob->space_obj_world_matrix); - } - else 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); - } - - BKE_constraint_targets_flush(curcon, &targets, 1); - } - } - } - /* NOTE: Don't use BKE_constraints_clear_evalob here as that will reset ob->constinv. */ - MEM_freeN(cob); - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Volumetric / Smoke sim - * \{ */ - -static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb, - OVERLAY_Data *data, - Object *ob, - ModifierData *md, - Scene *scene, - const float *color) -{ - FluidModifierData *fmd = (FluidModifierData *)md; - FluidDomainSettings *fds = fmd->domain; - - /* Don't show smoke before simulation starts, this could be made an option in the future. */ - const bool draw_velocity = (fds->draw_velocity && fds->fluid && - scene->r.cfra >= fds->point_cache[0]->startframe); - - /* Show gridlines only for slices with no interpolation. */ - const bool show_gridlines = (fds->show_gridlines && fds->fluid && - fds->axis_slice_method == AXIS_SLICE_SINGLE && - (fds->interp_method == FLUID_DISPLAY_INTERP_CLOSEST || - fds->coba_field == FLUID_DOMAIN_FIELD_FLAGS)); - - const bool color_with_flags = (fds->gridlines_color_field == FLUID_GRIDLINE_COLOR_TYPE_FLAGS); - - const bool color_range = (fds->gridlines_color_field == FLUID_GRIDLINE_COLOR_TYPE_RANGE && - fds->use_coba && fds->coba_field != FLUID_DOMAIN_FIELD_FLAGS); - - /* Small cube showing voxel size. */ - { - float min[3]; - madd_v3fl_v3fl_v3fl_v3i(min, fds->p0, fds->cell_size, fds->res_min); - float voxel_cubemat[4][4] = {{0.0f}}; - /* scale small cube to voxel size */ - voxel_cubemat[0][0] = fds->cell_size[0] / 2.0f; - voxel_cubemat[1][1] = fds->cell_size[1] / 2.0f; - voxel_cubemat[2][2] = fds->cell_size[2] / 2.0f; - 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); - } - - int slice_axis = -1; - - if (fds->axis_slice_method == AXIS_SLICE_SINGLE) { - float viewinv[4][4]; - DRW_view_viewmat_get(NULL, viewinv, true); - - const int axis = (fds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewinv[2]) : - fds->slice_axis - 1; - slice_axis = axis; - } - - if (draw_velocity) { - const bool use_needle = (fds->vector_draw_type == VECTOR_DRAW_NEEDLE); - const bool use_mac = (fds->vector_draw_type == VECTOR_DRAW_MAC); - const bool draw_mac_x = (fds->vector_draw_mac_components & VECTOR_DRAW_MAC_X); - const bool draw_mac_y = (fds->vector_draw_mac_components & VECTOR_DRAW_MAC_Y); - const bool draw_mac_z = (fds->vector_draw_mac_components & VECTOR_DRAW_MAC_Z); - const bool cell_centered = (fds->vector_field == FLUID_DOMAIN_VECTOR_FIELD_FORCE); - int line_count = 1; - if (use_needle) { - line_count = 6; - } - else if (use_mac) { - line_count = 3; - } - line_count *= fds->res[0] * fds->res[1] * fds->res[2]; - - if (fds->axis_slice_method == AXIS_SLICE_SINGLE) { - line_count /= fds->res[slice_axis]; - } - - DRW_smoke_ensure_velocity(fmd); - - GPUShader *sh = OVERLAY_shader_volume_velocity(use_needle, use_mac); - DRWShadingGroup *grp = DRW_shgroup_create(sh, data->psl->extra_ps[0]); - DRW_shgroup_uniform_texture(grp, "velocityX", fds->tex_velocity_x); - DRW_shgroup_uniform_texture(grp, "velocityY", fds->tex_velocity_y); - DRW_shgroup_uniform_texture(grp, "velocityZ", fds->tex_velocity_z); - DRW_shgroup_uniform_float_copy(grp, "displaySize", fds->vector_scale); - DRW_shgroup_uniform_float_copy(grp, "slicePosition", fds->slice_depth); - DRW_shgroup_uniform_vec3_copy(grp, "cellSize", fds->cell_size); - DRW_shgroup_uniform_vec3_copy(grp, "domainOriginOffset", fds->p0); - DRW_shgroup_uniform_ivec3_copy(grp, "adaptiveCellOffset", fds->res_min); - DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis); - DRW_shgroup_uniform_bool_copy(grp, "scaleWithMagnitude", fds->vector_scale_with_magnitude); - DRW_shgroup_uniform_bool_copy(grp, "isCellCentered", cell_centered); - - if (use_mac) { - DRW_shgroup_uniform_bool_copy(grp, "drawMACX", draw_mac_x); - DRW_shgroup_uniform_bool_copy(grp, "drawMACY", draw_mac_y); - DRW_shgroup_uniform_bool_copy(grp, "drawMACZ", draw_mac_z); - } - - DRW_shgroup_call_procedural_lines(grp, ob, line_count); - } - - if (show_gridlines) { - GPUShader *sh = OVERLAY_shader_volume_gridlines(color_with_flags, color_range); - DRWShadingGroup *grp = DRW_shgroup_create(sh, data->psl->extra_ps[0]); - DRW_shgroup_uniform_ivec3_copy(grp, "volumeSize", fds->res); - DRW_shgroup_uniform_float_copy(grp, "slicePosition", fds->slice_depth); - DRW_shgroup_uniform_vec3_copy(grp, "cellSize", fds->cell_size); - DRW_shgroup_uniform_vec3_copy(grp, "domainOriginOffset", fds->p0); - DRW_shgroup_uniform_ivec3_copy(grp, "adaptiveCellOffset", fds->res_min); - DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis); - - if (color_with_flags || color_range) { - DRW_fluid_ensure_flags(fmd); - DRW_shgroup_uniform_texture(grp, "flagTexture", fds->tex_flags); - } - - if (color_range) { - DRW_fluid_ensure_range_field(fmd); - DRW_shgroup_uniform_texture(grp, "fieldTexture", fds->tex_range_field); - DRW_shgroup_uniform_float_copy(grp, "lowerBound", fds->gridlines_lower_bound); - DRW_shgroup_uniform_float_copy(grp, "upperBound", fds->gridlines_upper_bound); - DRW_shgroup_uniform_vec4_copy(grp, "rangeColor", fds->gridlines_range_color); - DRW_shgroup_uniform_int_copy(grp, "cellFilter", fds->gridlines_cell_filter); - } - - const int line_count = 4 * fds->res[0] * fds->res[1] * fds->res[2] / fds->res[slice_axis]; - DRW_shgroup_call_procedural_lines(grp, ob, line_count); - } - - if (draw_velocity || show_gridlines) { - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ - -static void OVERLAY_object_center(OVERLAY_ExtraCallBuffers *cb, - Object *ob, - OVERLAY_PrivateData *pd, - const Scene *scene, - ViewLayer *view_layer) -{ - const bool is_library = ID_REAL_USERS(&ob->id) > 1 || ID_IS_LINKED(ob); - BKE_view_layer_synced_ensure(scene, view_layer); - if (ob == BKE_view_layer_active_object_get(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]; - /* Color Management: Exception here as texts are drawn in sRGB space directly. */ - 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; - /* Don't show fluid domain overlay extras outside of cache range. */ - const bool draw_volume = !from_dupli && - (md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) && - (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) && - (((FluidModifierData *)md)->domain != NULL) && - (scene->r.cfra >= - (((FluidModifierData *)md)->domain->cache_frame_start)) && - (scene->r.cfra <= (((FluidModifierData *)md)->domain->cache_frame_end)); - - 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, color, ob->boundtype, false); - } - /* Helpers for when we're transforming origins. */ - if (draw_xform) { - const float color_xform[4] = {0.15f, 0.15f, 0.15f, 0.7f}; - 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, scene, 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, color); - } - if (ob->rigidbody_object != NULL) { - OVERLAY_collision(cb, ob, color); - } - 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_blend_draw(OVERLAY_Data *vedata) -{ - DRW_draw_pass(vedata->psl->extra_blend_ps); -} - -void OVERLAY_extra_draw(OVERLAY_Data *vedata) -{ - DRW_draw_pass(vedata->psl->extra_ps[0]); -} - -void OVERLAY_extra_in_front_draw(OVERLAY_Data *vedata) -{ - DRW_draw_pass(vedata->psl->extra_ps[1]); -} - -void OVERLAY_extra_centers_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - DRW_draw_pass(psl->extra_grid_ps); - DRW_draw_pass(psl->extra_centers_ps); -} diff --git a/source/blender/draw/engines/overlay/overlay_extra.cc b/source/blender/draw/engines/overlay/overlay_extra.cc new file mode 100644 index 00000000000..8dd2f0d9a85 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_extra.cc @@ -0,0 +1,1623 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "UI_resources.h" + +#include "BKE_anim_path.h" +#include "BKE_camera.h" +#include "BKE_constraint.h" +#include "BKE_curve.h" +#include "BKE_global.h" +#include "BKE_mball.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_movieclip.h" +#include "BKE_object.h" +#include "BKE_tracking.h" + +#include "BLI_listbase.h" + +#include "DNA_camera_types.h" +#include "DNA_constraint_types.h" +#include "DNA_curve_types.h" +#include "DNA_fluid_types.h" +#include "DNA_lightprobe_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meta_types.h" +#include "DNA_modifier_types.h" +#include "DNA_pointcache_types.h" +#include "DNA_rigidbody_types.h" + +#include "DEG_depsgraph_query.h" + +#include "ED_view3d.h" + +#include "overlay_private.hh" + +#include "draw_common.h" +#include "draw_manager_text.h" + +void OVERLAY_extra_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_TextureList *txl = vedata->txl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + const bool is_select = DRW_state_is_select(); + + DRWState state_blend = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->extra_blend_ps, state_blend | pd->clipping_state); + DRW_PASS_CREATE(psl->extra_centers_ps, state_blend | pd->clipping_state); + + { + DRWState state = DRW_STATE_WRITE_COLOR; + + DRW_PASS_CREATE(psl->extra_grid_ps, state | pd->clipping_state); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DRWShadingGroup *grp; + struct GPUShader *sh = OVERLAY_shader_extra_grid(); + struct GPUTexture *tex = DRW_state_is_fbo() ? dtxl->depth : txl->dummy_depth_tx; + + pd->extra_grid_grp = grp = DRW_shgroup_create(sh, psl->extra_grid_ps); + DRW_shgroup_uniform_texture(grp, "depthBuffer", tex); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); + } + + 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 : + DRWState(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(is_select); + + grp = DRW_shgroup_create(sh, extra_ps); + DRW_shgroup_uniform_block(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(DRW_LOD_LOW)); + 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_cube_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->solid_quad = BUF_INSTANCE(grp_sub, format, DRW_cache_quad_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(grp, "globalsBlock", G_draw.block_ubo); + + grp_sub = DRW_shgroup_create_sub(grp); + DRW_shgroup_state_enable(grp_sub, DRW_STATE_DEPTH_LESS_EQUAL | 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_DEPTH_LESS_EQUAL | 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(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, is_select); + + grp = DRW_shgroup_create(sh, extra_ps); + DRW_shgroup_uniform_block(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, is_select); + + cb->extra_wire = grp = DRW_shgroup_create(sh, extra_ps); + DRW_shgroup_uniform_block(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(grp, "globalsBlock", G_draw.block_ubo); + + /* Buffer access for drawing isolated points, matching `extra_lines`. */ + cb->extra_points = BUF_POINT(grp, formats->point_extra); + } + { + 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(grp, "globalsBlock", G_draw.block_ubo); + + grp_sub = DRW_shgroup_create_sub(grp); + DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.color_active); + 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.color_select); + 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.color_deselect); + 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.color_library_select); + 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.color_library); + cb->center_deselected_lib = BUF_POINT(grp_sub, format); + } + } +} + +void OVERLAY_extra_point(OVERLAY_ExtraCallBuffers *cb, const float point[3], const float color[4]) +{ + DRW_buffer_add_entry(cb->extra_points, point, color); +} + +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_DRAW_IN_FRONT) != 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]; + const float col[4] = {UNPACK3(color), 0.0f /* No stipples. */}; + pack_v4_in_mat4(draw_mat, mat, col); + 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, + const float *color, + char boundtype, + bool around_origin) +{ + float center[3], size[3], tmp[4][4], final_mat[4][4]; + + if (ob->type == OB_MBALL && !BKE_mball_is_basis(ob)) { + return; + } + + const BoundBox *bb = BKE_object_boundbox_get(ob); + BoundBox bb_local; + if (bb == nullptr) { + const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f}; + BKE_boundbox_init_from_minmax(&bb_local, min, max); + bb = &bb_local; + } + + 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, const float *color) +{ + switch (ob->rigidbody_object->shape) { + case RB_SHAPE_BOX: + OVERLAY_bounds(cb, ob, color, OB_BOUND_BOX, true); + break; + case RB_SHAPE_SPHERE: + OVERLAY_bounds(cb, ob, color, OB_BOUND_SPHERE, true); + break; + case RB_SHAPE_CONE: + OVERLAY_bounds(cb, ob, color, OB_BOUND_CONE, true); + break; + case RB_SHAPE_CYLINDER: + OVERLAY_bounds(cb, ob, color, OB_BOUND_CYLINDER, true); + break; + case RB_SHAPE_CAPSULE: + OVERLAY_bounds(cb, ob, color, OB_BOUND_CAPSULE, true); + break; + } +} + +static void OVERLAY_texture_space(OVERLAY_ExtraCallBuffers *cb, Object *ob, const float *color) +{ + if (ob->data == nullptr) { + return; + } + + ID *ob_data = static_cast(ob->data); + float *texcoloc = nullptr; + float *texcosize = nullptr; + + switch (GS(ob_data->name)) { + case ID_ME: + BKE_mesh_texspace_get_reference((Mesh *)ob_data, nullptr, &texcoloc, &texcosize); + break; + case ID_CU_LEGACY: { + 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; + } + case ID_CV: + case ID_PT: + case ID_VO: { + /* No user defined texture space support. */ + break; + } + default: + BLI_assert(0); + } + + float mat[4][4]; + + if (texcoloc != nullptr && texcosize != nullptr) { + size_to_mat4(mat, texcosize); + copy_v3_v3(mat[3], texcoloc); + } + else { + unit_m4(mat); + } + + mul_m4_m4m4(mat, ob->obmat, mat); + + 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, nullptr); + float *color = DRW_color_background_blend_get(theme_id); + PartDeflect *pd = ob->pd; + Curve *cu = (ob->type == OB_CURVES_LEGACY) ? static_cast(ob->data) : nullptr; + + 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->anim_path_accum_length) { + instdata.size_x = instdata.size_y = instdata.size_z = pd->f_strength; + float pos[4]; + BKE_where_on_path(ob, 0.0f, pos, nullptr, nullptr, nullptr, nullptr); + 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); + + BKE_where_on_path(ob, 1.0f, pos, nullptr, nullptr, nullptr, nullptr); + 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 = static_cast(ob->data); + float *color_p; + DRW_object_wire_theme_get(ob, view_layer, &color_p); + /* Remove the alpha. */ + float color[4] = {UNPACK3(color_p), 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: clip_end has no meaning nowadays. + * In EEVEE, Only clip_sta is used shadow-mapping. + * Clip end is computed automatically based on light power. + * For now, always use the custom distance as clip_end. */ + instdata.clip_end = la->att_dist; + 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) { + /* Previous implementation was using the clipend distance as cone size. + * We cannot do this anymore so we use a fixed size of 10. (see T72871) */ + const float3 scale_vec = {10.0f, 10.0f, 10.0f}; + rescale_m4(instdata.mat, scale_vec); + /* 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()) { + const float color_inside[4] = {0.0f, 0.0f, 0.0f, 0.5f}; + const 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 Light-probe + * \{ */ + +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; + int theme_id = 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; + const bool show_data = (ob->base_flag & BASE_SELECTED) || DRW_state_is_select(); + + 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_cube, 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); + } + + /* Data dots */ + if (show_data) { + instdata.mat[0][3] = prb->grid_resolution_x; + instdata.mat[1][3] = prb->grid_resolution_y; + instdata.mat[2][3] = prb->grid_resolution_z; + /* Put theme id in matrix. */ + if (theme_id == TH_ACTIVE) { + instdata.mat[3][3] = 1.0; + } + else /* TH_SELECT */ { + instdata.mat[3][3] = 2.0; + } + + uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z; + DRWShadingGroup *grp = DRW_shgroup_create_sub(vedata->stl->pd->extra_grid_grp); + DRW_shgroup_uniform_mat4_copy(grp, "gridModelMatrix", instdata.mat); + DRW_shgroup_call_procedural_points(grp, nullptr, cell_count); + } + break; + case LIGHTPROBE_TYPE_PLANAR: + DRW_buffer_add_entry(cb->probe_planar, color_p, &instdata); + + if (DRW_state_is_select() && (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA)) { + DRW_buffer_add_entry(cb->solid_quad, 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 *ob, const float color[4]) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const bool is_select = DRW_state_is_select(); + + MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); + if (clip == nullptr) { + 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; + + float bundle_color_custom[3]; + float *bundle_color_solid = G_draw.block.color_bundle_solid; + float *bundle_color_unselected = G_draw.block.color_wire; + uchar text_color_selected[4], text_color_unselected[4]; + /* Color Management: Exception here as texts are drawn in sRGB space directly. */ + UI_GetThemeColor4ubv(TH_SELECT, text_color_selected); + UI_GetThemeColor4ubv(TH_TEXT, text_color_unselected); + + float camera_mat[4][4]; + BKE_tracking_get_camera_object_matrix(ob, camera_mat); + + 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); + + float object_imat[4][4]; + invert_m4_m4(object_imat, object_mat); + + mul_m4_m4m4(tracking_object_mat, ob->obmat, object_imat); + } + + ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object); + LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) { + 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) { + /* Meh, hardcoded srgb transform here. */ + /* TODO: change the actual DNA color to be linear. */ + srgb_to_linearrgb_v3_v3(bundle_color_custom, track->color); + bundle_color = bundle_color_custom; + } + 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(ob->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 = static_cast(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; + } + + 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 = static_cast(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; + + if (!is_stereo3d_cameras) { + /* Draw single camera. */ + DRW_buffer_add_entry_struct(cb->camera_frame, instdata); + } + + 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.color_wire); + } + + 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 = static_cast(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])); + /* Avoid division by 0. */ + if (ELEM(0.0f, scale[0], scale[1], scale[2])) { + return; + } + 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 positioning / 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, 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.color_wire; + float *constraint_color = G_draw.block.color_grid_axis_z; /* ? */ + + 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); + } + + /* Drawing the hook lines. */ + for (ModifierData *md = static_cast(ob->modifiers.first); md; md = md->next) { + if (md->type == eModifierType_Hook) { + HookModifierData *hmd = (HookModifierData *)md; + float center[3]; + mul_v3_m4v3(center, ob->obmat, hmd->cent); + if (hmd->object) { + OVERLAY_extra_line_dashed(cb, hmd->object->obmat[3], center, relation_color); + } + OVERLAY_extra_point(cb, center, 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, nullptr, CONSTRAINT_OBTYPE_OBJECT); + + for (curcon = static_cast(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 = nullptr; + + 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); + ListBase targets = {nullptr, nullptr}; + + if ((curcon->ui_expand_flag & (1 << 0)) && BKE_constraint_targets_get(curcon, &targets)) { + bConstraintTarget *ct; + + BKE_constraint_custom_object_space_init(cob, curcon); + + for (ct = static_cast(targets.first); ct; ct = ct->next) { + /* calculate target's matrix */ + if (ct->flag & CONSTRAINT_TAR_CUSTOM_SPACE) { + copy_m4_m4(ct->matrix, cob->space_obj_world_matrix); + } + else 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); + } + + BKE_constraint_targets_flush(curcon, &targets, 1); + } + } + } + /* NOTE: Don't use BKE_constraints_clear_evalob here as that will reset ob->constinv. */ + MEM_freeN(cob); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Volumetric / Smoke sim + * \{ */ + +static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb, + OVERLAY_Data *data, + Object *ob, + ModifierData *md, + Scene *scene, + const float *color) +{ + FluidModifierData *fmd = (FluidModifierData *)md; + FluidDomainSettings *fds = fmd->domain; + + /* Don't show smoke before simulation starts, this could be made an option in the future. */ + const bool draw_velocity = (fds->draw_velocity && fds->fluid && + scene->r.cfra >= fds->point_cache[0]->startframe); + + /* Show gridlines only for slices with no interpolation. */ + const bool show_gridlines = (fds->show_gridlines && fds->fluid && + fds->axis_slice_method == AXIS_SLICE_SINGLE && + (fds->interp_method == FLUID_DISPLAY_INTERP_CLOSEST || + fds->coba_field == FLUID_DOMAIN_FIELD_FLAGS)); + + const bool color_with_flags = (fds->gridlines_color_field == FLUID_GRIDLINE_COLOR_TYPE_FLAGS); + + const bool color_range = (fds->gridlines_color_field == FLUID_GRIDLINE_COLOR_TYPE_RANGE && + fds->use_coba && fds->coba_field != FLUID_DOMAIN_FIELD_FLAGS); + + /* Small cube showing voxel size. */ + { + float min[3]; + madd_v3fl_v3fl_v3fl_v3i(min, fds->p0, fds->cell_size, fds->res_min); + float voxel_cubemat[4][4] = {{0.0f}}; + /* scale small cube to voxel size */ + voxel_cubemat[0][0] = fds->cell_size[0] / 2.0f; + voxel_cubemat[1][1] = fds->cell_size[1] / 2.0f; + voxel_cubemat[2][2] = fds->cell_size[2] / 2.0f; + 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); + } + + int slice_axis = -1; + + if (fds->axis_slice_method == AXIS_SLICE_SINGLE) { + float viewinv[4][4]; + DRW_view_viewmat_get(nullptr, viewinv, true); + + const int axis = (fds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewinv[2]) : + fds->slice_axis - 1; + slice_axis = axis; + } + + if (draw_velocity) { + const bool use_needle = (fds->vector_draw_type == VECTOR_DRAW_NEEDLE); + const bool use_mac = (fds->vector_draw_type == VECTOR_DRAW_MAC); + const bool draw_mac_x = (fds->vector_draw_mac_components & VECTOR_DRAW_MAC_X); + const bool draw_mac_y = (fds->vector_draw_mac_components & VECTOR_DRAW_MAC_Y); + const bool draw_mac_z = (fds->vector_draw_mac_components & VECTOR_DRAW_MAC_Z); + const bool cell_centered = (fds->vector_field == FLUID_DOMAIN_VECTOR_FIELD_FORCE); + int line_count = 1; + if (use_needle) { + line_count = 6; + } + else if (use_mac) { + line_count = 3; + } + line_count *= fds->res[0] * fds->res[1] * fds->res[2]; + + if (fds->axis_slice_method == AXIS_SLICE_SINGLE) { + line_count /= fds->res[slice_axis]; + } + + DRW_smoke_ensure_velocity(fmd); + + GPUShader *sh = OVERLAY_shader_volume_velocity(use_needle, use_mac); + DRWShadingGroup *grp = DRW_shgroup_create(sh, data->psl->extra_ps[0]); + DRW_shgroup_uniform_texture(grp, "velocityX", fds->tex_velocity_x); + DRW_shgroup_uniform_texture(grp, "velocityY", fds->tex_velocity_y); + DRW_shgroup_uniform_texture(grp, "velocityZ", fds->tex_velocity_z); + DRW_shgroup_uniform_float_copy(grp, "displaySize", fds->vector_scale); + DRW_shgroup_uniform_float_copy(grp, "slicePosition", fds->slice_depth); + DRW_shgroup_uniform_vec3_copy(grp, "cellSize", fds->cell_size); + DRW_shgroup_uniform_vec3_copy(grp, "domainOriginOffset", fds->p0); + DRW_shgroup_uniform_ivec3_copy(grp, "adaptiveCellOffset", fds->res_min); + DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis); + DRW_shgroup_uniform_bool_copy(grp, "scaleWithMagnitude", fds->vector_scale_with_magnitude); + DRW_shgroup_uniform_bool_copy(grp, "isCellCentered", cell_centered); + + if (use_mac) { + DRW_shgroup_uniform_bool_copy(grp, "drawMACX", draw_mac_x); + DRW_shgroup_uniform_bool_copy(grp, "drawMACY", draw_mac_y); + DRW_shgroup_uniform_bool_copy(grp, "drawMACZ", draw_mac_z); + } + + DRW_shgroup_call_procedural_lines(grp, ob, line_count); + } + + if (show_gridlines) { + GPUShader *sh = OVERLAY_shader_volume_gridlines(color_with_flags, color_range); + DRWShadingGroup *grp = DRW_shgroup_create(sh, data->psl->extra_ps[0]); + DRW_shgroup_uniform_ivec3_copy(grp, "volumeSize", fds->res); + DRW_shgroup_uniform_float_copy(grp, "slicePosition", fds->slice_depth); + DRW_shgroup_uniform_vec3_copy(grp, "cellSize", fds->cell_size); + DRW_shgroup_uniform_vec3_copy(grp, "domainOriginOffset", fds->p0); + DRW_shgroup_uniform_ivec3_copy(grp, "adaptiveCellOffset", fds->res_min); + DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis); + + if (color_with_flags || color_range) { + DRW_fluid_ensure_flags(fmd); + DRW_shgroup_uniform_texture(grp, "flagTexture", fds->tex_flags); + } + + if (color_range) { + DRW_fluid_ensure_range_field(fmd); + DRW_shgroup_uniform_texture(grp, "fieldTexture", fds->tex_range_field); + DRW_shgroup_uniform_float_copy(grp, "lowerBound", fds->gridlines_lower_bound); + DRW_shgroup_uniform_float_copy(grp, "upperBound", fds->gridlines_upper_bound); + DRW_shgroup_uniform_vec4_copy(grp, "rangeColor", fds->gridlines_range_color); + DRW_shgroup_uniform_int_copy(grp, "cellFilter", fds->gridlines_cell_filter); + } + + const int line_count = 4 * fds->res[0] * fds->res[1] * fds->res[2] / fds->res[slice_axis]; + DRW_shgroup_call_procedural_lines(grp, ob, line_count); + } + + if (draw_velocity || show_gridlines) { + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +static void OVERLAY_object_center(OVERLAY_ExtraCallBuffers *cb, + Object *ob, + OVERLAY_PrivateData *pd, + const Scene *scene, + ViewLayer *view_layer) +{ + const bool is_library = ID_REAL_USERS(&ob->id) > 1 || ID_IS_LINKED(ob); + BKE_view_layer_synced_ensure(scene, view_layer); + if (ob == BKE_view_layer_active_object_get(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]; + /* Color Management: Exception here as texts are drawn in sRGB space directly. */ + 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 = nullptr; + + 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; + /* Don't show fluid domain overlay extras outside of cache range. */ + const bool draw_volume = !from_dupli && + (md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) && + (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) && + (((FluidModifierData *)md)->domain != nullptr) && + (scene->r.cfra >= + (((FluidModifierData *)md)->domain->cache_frame_start)) && + (scene->r.cfra <= (((FluidModifierData *)md)->domain->cache_frame_end)); + + 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, color, ob->boundtype, false); + } + /* Helpers for when we're transforming origins. */ + if (draw_xform) { + const float color_xform[4] = {0.15f, 0.15f, 0.15f, 0.7f}; + 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, scene, 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, color); + } + if (ob->rigidbody_object != nullptr) { + OVERLAY_collision(cb, ob, color); + } + 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_blend_draw(OVERLAY_Data *vedata) +{ + DRW_draw_pass(vedata->psl->extra_blend_ps); +} + +void OVERLAY_extra_draw(OVERLAY_Data *vedata) +{ + DRW_draw_pass(vedata->psl->extra_ps[0]); +} + +void OVERLAY_extra_in_front_draw(OVERLAY_Data *vedata) +{ + DRW_draw_pass(vedata->psl->extra_ps[1]); +} + +void OVERLAY_extra_centers_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + DRW_draw_pass(psl->extra_grid_ps); + 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 deleted file mode 100644 index bf06600eb33..00000000000 --- a/source/blender/draw/engines/overlay/overlay_facing.c +++ /dev/null @@ -1,73 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "BKE_paint.h" -#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; - - for (int i = 0; i < 2; i++) { - /* Non Meshes Pass (Camera, empties, lights ...) */ - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA; - DRW_PASS_CREATE(psl->facing_ps[i], state | pd->clipping_state); - - GPUShader *sh = OVERLAY_shader_facing(); - pd->facing_grp[i] = DRW_shgroup_create(sh, psl->facing_ps[i]); - DRW_shgroup_uniform_block(pd->facing_grp[i], "globalsBlock", G_draw.block_ubo); - } - - if (!pd->use_in_front) { - pd->facing_grp[IN_FRONT] = pd->facing_grp[NOT_IN_FRONT]; - } -} - -void OVERLAY_facing_cache_populate(OVERLAY_Data *vedata, Object *ob) -{ - OVERLAY_PrivateData *pd = vedata->stl->pd; - - if (pd->xray_enabled) { - return; - } - - const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; - - if (use_sculpt_pbvh) { - DRW_shgroup_call_sculpt(pd->facing_grp[is_xray], ob, false, false); - } - else { - struct GPUBatch *geom = DRW_cache_object_surface_get(ob); - if (geom) { - DRW_shgroup_call(pd->facing_grp[is_xray], geom, ob); - } - } -} - -void OVERLAY_facing_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - DRW_draw_pass(psl->facing_ps[NOT_IN_FRONT]); -} - -void OVERLAY_facing_infront_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - DRW_draw_pass(psl->facing_ps[IN_FRONT]); -} diff --git a/source/blender/draw/engines/overlay/overlay_facing.cc b/source/blender/draw/engines/overlay/overlay_facing.cc new file mode 100644 index 00000000000..9a501c8f1bb --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_facing.cc @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "BKE_paint.h" +#include "DRW_render.h" + +#include "overlay_private.hh" + +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; + + for (int i = 0; i < 2; i++) { + /* Non Meshes Pass (Camera, empties, lights ...) */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->facing_ps[i], state | pd->clipping_state); + + GPUShader *sh = OVERLAY_shader_facing(); + pd->facing_grp[i] = DRW_shgroup_create(sh, psl->facing_ps[i]); + DRW_shgroup_uniform_block(pd->facing_grp[i], "globalsBlock", G_draw.block_ubo); + } + + if (!pd->use_in_front) { + pd->facing_grp[IN_FRONT] = pd->facing_grp[NOT_IN_FRONT]; + } +} + +void OVERLAY_facing_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + + if (pd->xray_enabled) { + return; + } + + const DRWContextState *draw_ctx = DRW_context_state_get(); + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + !DRW_state_is_image_render(); + const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; + + if (use_sculpt_pbvh) { + DRW_shgroup_call_sculpt(pd->facing_grp[is_xray], ob, false, false); + } + else { + struct GPUBatch *geom = DRW_cache_object_surface_get(ob); + if (geom) { + DRW_shgroup_call(pd->facing_grp[is_xray], geom, ob); + } + } +} + +void OVERLAY_facing_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + DRW_draw_pass(psl->facing_ps[NOT_IN_FRONT]); +} + +void OVERLAY_facing_infront_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + DRW_draw_pass(psl->facing_ps[IN_FRONT]); +} diff --git a/source/blender/draw/engines/overlay/overlay_fade.c b/source/blender/draw/engines/overlay/overlay_fade.c deleted file mode 100644 index 056e02a04e1..00000000000 --- a/source/blender/draw/engines/overlay/overlay_fade.c +++ /dev/null @@ -1,83 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2020 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "BKE_paint.h" -#include "DRW_render.h" - -#include "ED_view3d.h" - -#include "overlay_private.h" - -void OVERLAY_fade_init(OVERLAY_Data *UNUSED(vedata)) -{ -} - -void OVERLAY_fade_cache_init(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_PrivateData *pd = vedata->stl->pd; - - for (int i = 0; i < 2; i++) { - /* Non Meshes Pass (Camera, empties, lights ...) */ - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA; - DRW_PASS_CREATE(psl->fade_ps[i], state | pd->clipping_state); - - GPUShader *sh = OVERLAY_shader_uniform_color(); - pd->fade_grp[i] = DRW_shgroup_create(sh, psl->fade_ps[i]); - - const DRWContextState *draw_ctx = DRW_context_state_get(); - float color[4]; - ED_view3d_background_color_get(draw_ctx->scene, draw_ctx->v3d, color); - color[3] = pd->overlay.fade_alpha; - if (draw_ctx->v3d->shading.background_type == V3D_SHADING_BACKGROUND_THEME) { - srgb_to_linearrgb_v4(color, color); - } - DRW_shgroup_uniform_vec4_copy(pd->fade_grp[i], "color", color); - } - - if (!pd->use_in_front) { - pd->fade_grp[IN_FRONT] = pd->fade_grp[NOT_IN_FRONT]; - } -} - -void OVERLAY_fade_cache_populate(OVERLAY_Data *vedata, Object *ob) -{ - OVERLAY_PrivateData *pd = vedata->stl->pd; - - if (pd->xray_enabled) { - return; - } - - const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; - - if (use_sculpt_pbvh) { - DRW_shgroup_call_sculpt(pd->fade_grp[is_xray], ob, false, false); - } - else { - struct GPUBatch *geom = DRW_cache_object_surface_get(ob); - if (geom) { - DRW_shgroup_call(pd->fade_grp[is_xray], geom, ob); - } - } -} - -void OVERLAY_fade_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - DRW_draw_pass(psl->fade_ps[NOT_IN_FRONT]); -} - -void OVERLAY_fade_infront_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - DRW_draw_pass(psl->fade_ps[IN_FRONT]); -} diff --git a/source/blender/draw/engines/overlay/overlay_fade.cc b/source/blender/draw/engines/overlay/overlay_fade.cc new file mode 100644 index 00000000000..138226c3e2e --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_fade.cc @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2020 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "BKE_paint.h" +#include "DRW_render.h" + +#include "ED_view3d.h" + +#include "overlay_private.hh" + +void OVERLAY_fade_init(OVERLAY_Data *UNUSED(vedata)) +{ +} + +void OVERLAY_fade_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + + for (int i = 0; i < 2; i++) { + /* Non Meshes Pass (Camera, empties, lights ...) */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->fade_ps[i], state | pd->clipping_state); + + GPUShader *sh = OVERLAY_shader_uniform_color(); + pd->fade_grp[i] = DRW_shgroup_create(sh, psl->fade_ps[i]); + + const DRWContextState *draw_ctx = DRW_context_state_get(); + float color[4]; + ED_view3d_background_color_get(draw_ctx->scene, draw_ctx->v3d, color); + color[3] = pd->overlay.fade_alpha; + if (draw_ctx->v3d->shading.background_type == V3D_SHADING_BACKGROUND_THEME) { + srgb_to_linearrgb_v4(color, color); + } + DRW_shgroup_uniform_vec4_copy(pd->fade_grp[i], "color", color); + } + + if (!pd->use_in_front) { + pd->fade_grp[IN_FRONT] = pd->fade_grp[NOT_IN_FRONT]; + } +} + +void OVERLAY_fade_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + + if (pd->xray_enabled) { + return; + } + + const DRWContextState *draw_ctx = DRW_context_state_get(); + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + !DRW_state_is_image_render(); + const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; + + if (use_sculpt_pbvh) { + DRW_shgroup_call_sculpt(pd->fade_grp[is_xray], ob, false, false); + } + else { + struct GPUBatch *geom = DRW_cache_object_surface_get(ob); + if (geom) { + DRW_shgroup_call(pd->fade_grp[is_xray], geom, ob); + } + } +} + +void OVERLAY_fade_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + DRW_draw_pass(psl->fade_ps[NOT_IN_FRONT]); +} + +void OVERLAY_fade_infront_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + DRW_draw_pass(psl->fade_ps[IN_FRONT]); +} diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c deleted file mode 100644 index 9531b0dd983..00000000000 --- a/source/blender/draw/engines/overlay/overlay_gpencil.c +++ /dev/null @@ -1,471 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2020 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "DRW_render.h" - -#include "BKE_gpencil.h" - -#include "UI_resources.h" - -#include "DNA_gpencil_types.h" - -#include "DEG_depsgraph_query.h" - -#include "ED_view3d.h" - -#include "overlay_private.h" - -#include "draw_common.h" -#include "draw_manager_text.h" - -void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_PrivateData *pd = vedata->stl->pd; - struct GPUShader *sh; - DRWShadingGroup *grp; - - /* Default: Display nothing. */ - pd->edit_gpencil_points_grp = NULL; - pd->edit_gpencil_wires_grp = NULL; - psl->edit_gpencil_ps = NULL; - - pd->edit_gpencil_curve_handle_grp = NULL; - pd->edit_gpencil_curve_points_grp = NULL; - psl->edit_gpencil_curve_ps = NULL; - - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - Object *ob = draw_ctx->obact; - bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL; - Scene *scene = draw_ctx->scene; - ToolSettings *ts = scene->toolsettings; - - if (gpd == NULL || ob->type != OB_GPENCIL) { - return; - } - - /* For sculpt show only if mask mode, and only points if not stroke mode. */ - const bool use_sculpt_mask = (GPENCIL_SCULPT_MODE(gpd) && - GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt)); - const bool show_sculpt_points = (GPENCIL_SCULPT_MODE(gpd) && - (ts->gpencil_selectmode_sculpt & - (GP_SCULPT_MASK_SELECTMODE_POINT | - GP_SCULPT_MASK_SELECTMODE_SEGMENT))); - - /* For vertex paint show only if mask mode, and only points if not stroke mode. */ - bool use_vertex_mask = (GPENCIL_VERTEX_MODE(gpd) && - GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex)); - const bool show_vertex_points = (GPENCIL_VERTEX_MODE(gpd) && - (ts->gpencil_selectmode_vertex & - (GP_VERTEX_MASK_SELECTMODE_POINT | - GP_VERTEX_MASK_SELECTMODE_SEGMENT))); - - /* If Sculpt or Vertex mode and the mask is disabled, the select must be hidden. */ - const bool hide_select = ((GPENCIL_SCULPT_MODE(gpd) && !use_sculpt_mask) || - (GPENCIL_VERTEX_MODE(gpd) && !use_vertex_mask)); - - const bool do_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - const bool show_multi_edit_lines = (do_multiedit) && - ((v3d->gp_flag & (V3D_GP_SHOW_MULTIEDIT_LINES | - V3D_GP_SHOW_EDIT_LINES)) != 0); - - const bool show_lines = (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) || show_multi_edit_lines; - - const bool hide_lines = !GPENCIL_EDIT_MODE(gpd) && !GPENCIL_WEIGHT_MODE(gpd) && - !use_sculpt_mask && !use_vertex_mask && !show_lines; - - /* Special case when vertex paint and multiedit lines. */ - if (do_multiedit && show_multi_edit_lines && GPENCIL_VERTEX_MODE(gpd)) { - use_vertex_mask = true; - } - - const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); - - /* Show Edit points if: - * Edit mode: Not in Stroke selection mode - * Sculpt mode: If use Mask and not Stroke mode - * Weight mode: Always - * Vertex mode: If use Mask and not Stroke mode - */ - const bool show_points = show_sculpt_points || is_weight_paint || show_vertex_points || - (GPENCIL_EDIT_MODE(gpd) && - (ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE)); - - if ((!GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) && - ((!GPENCIL_VERTEX_MODE(gpd) && !GPENCIL_PAINT_MODE(gpd)) || use_vertex_mask)) { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - DRW_STATE_BLEND_ALPHA; - DRW_PASS_CREATE(psl->edit_gpencil_ps, state | pd->clipping_state); - - if (show_lines && !hide_lines) { - sh = OVERLAY_shader_edit_gpencil_wire(); - pd->edit_gpencil_wires_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", show_multi_edit_lines); - DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint); - DRW_shgroup_uniform_bool_copy(grp, "hideSelect", hide_select); - DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity); - DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp); - } - - if (show_points && !hide_select) { - sh = OVERLAY_shader_edit_gpencil_point(); - pd->edit_gpencil_points_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", do_multiedit); - DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint); - DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity); - DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp); - } - } - - /* Handles and curve point for Curve Edit sub-mode. */ - if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) { - DRWState state = DRW_STATE_WRITE_COLOR; - DRW_PASS_CREATE(psl->edit_gpencil_curve_ps, state | pd->clipping_state); - - /* Edit lines. */ - if (show_lines) { - sh = OVERLAY_shader_edit_gpencil_wire(); - pd->edit_gpencil_wires_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_curve_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", show_multi_edit_lines); - DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint); - DRW_shgroup_uniform_bool_copy(grp, "hideSelect", hide_select); - DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity); - DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp); - } - - sh = OVERLAY_shader_edit_curve_handle(); - pd->edit_gpencil_curve_handle_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_curve_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_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display); - DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); - - sh = OVERLAY_shader_edit_curve_point(); - pd->edit_gpencil_curve_points_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_curve_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_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display); - } - - /* control points for primitives and speed guide */ - const bool is_cppoint = (gpd->runtime.tot_cp_points > 0); - const bool is_speed_guide = (ts->gp_sculpt.guide.use_guide && - (draw_ctx->object_mode == OB_MODE_PAINT_GPENCIL)); - const bool is_show_gizmo = (((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) && - ((v3d->gizmo_flag & V3D_GIZMO_HIDE_TOOL) == 0)); - - if ((is_cppoint || is_speed_guide) && (is_show_gizmo)) { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; - DRW_PASS_CREATE(psl->edit_gpencil_gizmos_ps, state); - - sh = OVERLAY_shader_edit_gpencil_guide_point(); - grp = DRW_shgroup_create(sh, psl->edit_gpencil_gizmos_ps); - - if (gpd->runtime.cp_points != NULL) { - for (int i = 0; i < gpd->runtime.tot_cp_points; i++) { - bGPDcontrolpoint *cp = &gpd->runtime.cp_points[i]; - grp = DRW_shgroup_create_sub(grp); - DRW_shgroup_uniform_vec3_copy(grp, "pPosition", &cp->x); - DRW_shgroup_uniform_float_copy(grp, "pSize", cp->size * 0.8f * G_draw.block.size_pixel); - DRW_shgroup_uniform_vec4_copy(grp, "pColor", cp->color); - DRW_shgroup_call_procedural_points(grp, NULL, 1); - } - } - - if (ts->gp_sculpt.guide.use_guide) { - float color[4]; - if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_CUSTOM) { - UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color); - DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.location); - } - else if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_OBJECT && - ts->gp_sculpt.guide.reference_object != NULL) { - UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color); - DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.reference_object->loc); - } - else { - UI_GetThemeColor4fv(TH_REDALERT, color); - DRW_shgroup_uniform_vec3_copy(grp, "pPosition", scene->cursor.location); - } - DRW_shgroup_uniform_vec4_copy(grp, "pColor", color); - DRW_shgroup_uniform_float_copy(grp, "pSize", 8.0f * G_draw.block.size_pixel); - DRW_shgroup_call_procedural_points(grp, NULL, 1); - } - } -} - -void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_PrivateData *pd = vedata->stl->pd; - struct GPUShader *sh; - DRWShadingGroup *grp; - - /* Default: Display nothing. */ - psl->gpencil_canvas_ps = NULL; - - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - Object *ob = draw_ctx->obact; - bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL; - Scene *scene = draw_ctx->scene; - ToolSettings *ts = scene->toolsettings; - const View3DCursor *cursor = &scene->cursor; - - pd->edit_curve.show_handles = v3d->overlay.handle_display != CURVE_HANDLE_NONE; - pd->edit_curve.handle_display = v3d->overlay.handle_display; - - if (gpd == NULL || ob->type != OB_GPENCIL) { - return; - } - - const bool show_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0; - const bool show_grid = (v3d->gp_flag & V3D_GP_SHOW_GRID) != 0 && - ((ts->gpencil_v3d_align & - (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) == 0); - const bool grid_xray = (v3d->gp_flag & V3D_GP_SHOW_GRID_XRAY); - - if (show_grid && show_overlays) { - const char *grid_unit = NULL; - float mat[4][4]; - float col_grid[4]; - float size[2]; - - /* set color */ - copy_v3_v3(col_grid, gpd->grid.color); - col_grid[3] = max_ff(v3d->overlay.gpencil_grid_opacity, 0.01f); - - copy_m4_m4(mat, ob->obmat); - - /* Rotate and scale except align to cursor. */ - bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); - if (gpl != NULL) { - if (ts->gp_sculpt.lock_axis != GP_LOCKAXIS_CURSOR) { - float matrot[3][3]; - copy_m3_m4(matrot, gpl->layer_mat); - mul_m4_m4m3(mat, mat, matrot); - } - } - - float viewinv[4][4]; - /* Set the grid in the selected axis */ - switch (ts->gp_sculpt.lock_axis) { - case GP_LOCKAXIS_X: - swap_v4_v4(mat[0], mat[2]); - break; - case GP_LOCKAXIS_Y: - swap_v4_v4(mat[1], mat[2]); - break; - case GP_LOCKAXIS_Z: - /* Default. */ - break; - case GP_LOCKAXIS_CURSOR: - loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, (float[3]){1, 1, 1}); - break; - case GP_LOCKAXIS_VIEW: - /* view aligned */ - DRW_view_viewmat_get(NULL, viewinv, true); - copy_v3_v3(mat[0], viewinv[0]); - copy_v3_v3(mat[1], viewinv[1]); - break; - } - - /* Move the grid to the right location depending of the align type. - * This is required only for 3D Cursor or Origin. */ - if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) { - copy_v3_v3(mat[3], cursor->location); - } - else if (ts->gpencil_v3d_align & GP_PROJECT_VIEWSPACE) { - copy_v3_v3(mat[3], ob->obmat[3]); - } - - translate_m4(mat, gpd->grid.offset[0], gpd->grid.offset[1], 0.0f); - mul_v2_v2fl(size, gpd->grid.scale, 2.0f * ED_scene_grid_scale(scene, &grid_unit)); - rescale_m4(mat, (float[3]){size[0], size[1], 0.0f}); - - /* Apply layer loc transform, except cursor mode. */ - if ((gpl != NULL) && (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { - add_v3_v3(mat[3], gpl->layer_mat[3]); - } - - const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines; - const int line_count = gridlines * 4 + 2; - - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; - state |= (grid_xray) ? DRW_STATE_DEPTH_ALWAYS : DRW_STATE_DEPTH_LESS_EQUAL; - - DRW_PASS_CREATE(psl->gpencil_canvas_ps, state); - - sh = OVERLAY_shader_gpencil_canvas(); - grp = DRW_shgroup_create(sh, psl->gpencil_canvas_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_vec4_copy(grp, "color", col_grid); - DRW_shgroup_uniform_vec3_copy(grp, "xAxis", mat[0]); - DRW_shgroup_uniform_vec3_copy(grp, "yAxis", mat[1]); - DRW_shgroup_uniform_vec3_copy(grp, "origin", mat[3]); - DRW_shgroup_uniform_int_copy(grp, "halfLineCount", line_count / 2); - DRW_shgroup_call_procedural_lines(grp, NULL, line_count); - } -} - -static void OVERLAY_edit_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob) -{ - OVERLAY_PrivateData *pd = vedata->stl->pd; - bGPdata *gpd = (bGPdata *)ob->data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - - /* Overlay is only for active object. */ - if (ob != draw_ctx->obact) { - return; - } - - if (pd->edit_gpencil_wires_grp) { - DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_wires_grp); - DRW_shgroup_uniform_vec4_copy(grp, "gpEditColor", gpd->line_color); - - struct GPUBatch *geom = DRW_cache_gpencil_edit_lines_get(ob, pd->cfra); - DRW_shgroup_call_no_cull(pd->edit_gpencil_wires_grp, geom, ob); - } - - if (pd->edit_gpencil_points_grp) { - const bool show_direction = (v3d->gp_flag & V3D_GP_SHOW_STROKE_DIRECTION) != 0; - - DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_points_grp); - DRW_shgroup_uniform_float_copy(grp, "doStrokeEndpoints", show_direction); - - struct GPUBatch *geom = DRW_cache_gpencil_edit_points_get(ob, pd->cfra); - DRW_shgroup_call_no_cull(grp, geom, ob); - } - - if (pd->edit_gpencil_curve_handle_grp) { - struct GPUBatch *geom = DRW_cache_gpencil_edit_curve_handles_get(ob, pd->cfra); - if (geom) { - DRW_shgroup_call_no_cull(pd->edit_gpencil_curve_handle_grp, geom, ob); - } - } - - if (pd->edit_gpencil_curve_points_grp) { - struct GPUBatch *geom = DRW_cache_gpencil_edit_curve_points_get(ob, pd->cfra); - if (geom) { - DRW_shgroup_call_no_cull(pd->edit_gpencil_curve_points_grp, geom, ob); - } - } -} - -static void overlay_gpencil_draw_stroke_color_name(bGPDlayer *UNUSED(gpl), - bGPDframe *UNUSED(gpf), - bGPDstroke *gps, - void *thunk) -{ - Object *ob = (Object *)thunk; - Material *ma = BKE_object_material_get_eval(ob, gps->mat_nr + 1); - if (ma == NULL) { - return; - } - 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)) { - return; - } - /* check if the color is visible */ - if (gp_style->flag & GP_MATERIAL_HIDE) { - return; - } - /* only if selected */ - if (gps->flag & GP_STROKE_SELECT) { - for (int i = 0; i < gps->totpoints; i++) { - bGPDspoint *pt = &gps->points[i]; - /* Draw name at the first selected point. */ - if (pt->flag & GP_SPOINT_SELECT) { - 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); - - float fpt[3]; - mul_v3_m4v3(fpt, ob->obmat, &pt->x); - - struct DRWTextStore *dt = DRW_text_cache_ensure(); - 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; - } - } - } -} - -static void OVERLAY_gpencil_color_names(Object *ob) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - int cfra = DEG_get_ctime(draw_ctx->depsgraph); - - BKE_gpencil_visible_stroke_advanced_iter( - NULL, ob, NULL, overlay_gpencil_draw_stroke_color_name, ob, false, cfra); -} - -void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - - bGPdata *gpd = (bGPdata *)ob->data; - if (gpd == NULL) { - return; - } - - if (GPENCIL_ANY_MODE(gpd)) { - OVERLAY_edit_gpencil_cache_populate(vedata, ob); - } - - /* don't show object extras in set's */ - if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) { - if ((v3d->gp_flag & V3D_GP_SHOW_MATERIAL_NAME) && (ob->mode == OB_MODE_EDIT_GPENCIL) && - DRW_state_show_text()) { - OVERLAY_gpencil_color_names(ob); - } - } -} - -void OVERLAY_gpencil_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - if (psl->gpencil_canvas_ps) { - DRW_draw_pass(psl->gpencil_canvas_ps); - } -} - -void OVERLAY_edit_gpencil_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - if (psl->edit_gpencil_gizmos_ps) { - DRW_draw_pass(psl->edit_gpencil_gizmos_ps); - } - - if (psl->edit_gpencil_ps) { - DRW_draw_pass(psl->edit_gpencil_ps); - } - - /* Curve edit handles. */ - if (psl->edit_gpencil_curve_ps) { - DRW_draw_pass(psl->edit_gpencil_curve_ps); - } -} diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.cc b/source/blender/draw/engines/overlay/overlay_gpencil.cc new file mode 100644 index 00000000000..f72bf81bf57 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_gpencil.cc @@ -0,0 +1,474 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2020 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "BKE_gpencil.h" + +#include "UI_resources.h" + +#include "DNA_gpencil_types.h" + +#include "DEG_depsgraph_query.h" + +#include "ED_view3d.h" + +#include "overlay_private.hh" + +#include "draw_common.h" +#include "draw_manager_text.h" + +void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + struct GPUShader *sh; + DRWShadingGroup *grp; + + /* Default: Display nothing. */ + pd->edit_gpencil_points_grp = nullptr; + pd->edit_gpencil_wires_grp = nullptr; + psl->edit_gpencil_ps = nullptr; + + pd->edit_gpencil_curve_handle_grp = nullptr; + pd->edit_gpencil_curve_points_grp = nullptr; + psl->edit_gpencil_curve_ps = nullptr; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + Object *ob = draw_ctx->obact; + bGPdata *gpd = ob ? (bGPdata *)ob->data : nullptr; + Scene *scene = draw_ctx->scene; + ToolSettings *ts = scene->toolsettings; + + if (gpd == nullptr || ob->type != OB_GPENCIL) { + return; + } + + /* For sculpt show only if mask mode, and only points if not stroke mode. */ + const bool use_sculpt_mask = (GPENCIL_SCULPT_MODE(gpd) && + GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt)); + const bool show_sculpt_points = (GPENCIL_SCULPT_MODE(gpd) && + (ts->gpencil_selectmode_sculpt & + (GP_SCULPT_MASK_SELECTMODE_POINT | + GP_SCULPT_MASK_SELECTMODE_SEGMENT))); + + /* For vertex paint show only if mask mode, and only points if not stroke mode. */ + bool use_vertex_mask = (GPENCIL_VERTEX_MODE(gpd) && + GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex)); + const bool show_vertex_points = (GPENCIL_VERTEX_MODE(gpd) && + (ts->gpencil_selectmode_vertex & + (GP_VERTEX_MASK_SELECTMODE_POINT | + GP_VERTEX_MASK_SELECTMODE_SEGMENT))); + + /* If Sculpt or Vertex mode and the mask is disabled, the select must be hidden. */ + const bool hide_select = ((GPENCIL_SCULPT_MODE(gpd) && !use_sculpt_mask) || + (GPENCIL_VERTEX_MODE(gpd) && !use_vertex_mask)); + + const bool do_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const bool show_multi_edit_lines = (do_multiedit) && + ((v3d->gp_flag & (V3D_GP_SHOW_MULTIEDIT_LINES | + V3D_GP_SHOW_EDIT_LINES)) != 0); + + const bool show_lines = (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) || show_multi_edit_lines; + + const bool hide_lines = !GPENCIL_EDIT_MODE(gpd) && !GPENCIL_WEIGHT_MODE(gpd) && + !use_sculpt_mask && !use_vertex_mask && !show_lines; + + /* Special case when vertex paint and multiedit lines. */ + if (do_multiedit && show_multi_edit_lines && GPENCIL_VERTEX_MODE(gpd)) { + use_vertex_mask = true; + } + + const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); + + /* Show Edit points if: + * Edit mode: Not in Stroke selection mode + * Sculpt mode: If use Mask and not Stroke mode + * Weight mode: Always + * Vertex mode: If use Mask and not Stroke mode + */ + const bool show_points = show_sculpt_points || is_weight_paint || show_vertex_points || + (GPENCIL_EDIT_MODE(gpd) && + (ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE)); + + if ((!GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) && + ((!GPENCIL_VERTEX_MODE(gpd) && !GPENCIL_PAINT_MODE(gpd)) || use_vertex_mask)) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | + DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->edit_gpencil_ps, state | pd->clipping_state); + + if (show_lines && !hide_lines) { + sh = OVERLAY_shader_edit_gpencil_wire(); + pd->edit_gpencil_wires_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", show_multi_edit_lines); + DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint); + DRW_shgroup_uniform_bool_copy(grp, "hideSelect", hide_select); + DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity); + DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp); + } + + if (show_points && !hide_select) { + sh = OVERLAY_shader_edit_gpencil_point(); + pd->edit_gpencil_points_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", do_multiedit); + DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint); + DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity); + DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp); + } + } + + /* Handles and curve point for Curve Edit sub-mode. */ + if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) { + DRWState state = DRW_STATE_WRITE_COLOR; + DRW_PASS_CREATE(psl->edit_gpencil_curve_ps, state | pd->clipping_state); + + /* Edit lines. */ + if (show_lines) { + sh = OVERLAY_shader_edit_gpencil_wire(); + pd->edit_gpencil_wires_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_curve_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", show_multi_edit_lines); + DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint); + DRW_shgroup_uniform_bool_copy(grp, "hideSelect", hide_select); + DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity); + DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp); + } + + sh = OVERLAY_shader_edit_curve_handle(); + pd->edit_gpencil_curve_handle_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_curve_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_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA); + + sh = OVERLAY_shader_edit_curve_point(); + pd->edit_gpencil_curve_points_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_curve_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_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display); + } + + /* control points for primitives and speed guide */ + const bool is_cppoint = (gpd->runtime.tot_cp_points > 0); + const bool is_speed_guide = (ts->gp_sculpt.guide.use_guide && + (draw_ctx->object_mode == OB_MODE_PAINT_GPENCIL)); + const bool is_show_gizmo = (((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) && + ((v3d->gizmo_flag & V3D_GIZMO_HIDE_TOOL) == 0)); + + if ((is_cppoint || is_speed_guide) && (is_show_gizmo)) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->edit_gpencil_gizmos_ps, state); + + sh = OVERLAY_shader_edit_gpencil_guide_point(); + grp = DRW_shgroup_create(sh, psl->edit_gpencil_gizmos_ps); + + if (gpd->runtime.cp_points != nullptr) { + for (int i = 0; i < gpd->runtime.tot_cp_points; i++) { + bGPDcontrolpoint *cp = &gpd->runtime.cp_points[i]; + grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_uniform_vec3_copy(grp, "pPosition", &cp->x); + DRW_shgroup_uniform_float_copy(grp, "pSize", cp->size * 0.8f * G_draw.block.size_pixel); + DRW_shgroup_uniform_vec4_copy(grp, "pColor", cp->color); + DRW_shgroup_call_procedural_points(grp, nullptr, 1); + } + } + + if (ts->gp_sculpt.guide.use_guide) { + float color[4]; + if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_CUSTOM) { + UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color); + DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.location); + } + else if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_OBJECT && + ts->gp_sculpt.guide.reference_object != nullptr) { + UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color); + DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.reference_object->loc); + } + else { + UI_GetThemeColor4fv(TH_REDALERT, color); + DRW_shgroup_uniform_vec3_copy(grp, "pPosition", scene->cursor.location); + } + DRW_shgroup_uniform_vec4_copy(grp, "pColor", color); + DRW_shgroup_uniform_float_copy(grp, "pSize", 8.0f * G_draw.block.size_pixel); + DRW_shgroup_call_procedural_points(grp, nullptr, 1); + } + } +} + +void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + struct GPUShader *sh; + DRWShadingGroup *grp; + + /* Default: Display nothing. */ + psl->gpencil_canvas_ps = nullptr; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + Object *ob = draw_ctx->obact; + bGPdata *gpd = ob ? (bGPdata *)ob->data : nullptr; + Scene *scene = draw_ctx->scene; + ToolSettings *ts = scene->toolsettings; + const View3DCursor *cursor = &scene->cursor; + + pd->edit_curve.show_handles = v3d->overlay.handle_display != CURVE_HANDLE_NONE; + pd->edit_curve.handle_display = v3d->overlay.handle_display; + + if (gpd == nullptr || ob->type != OB_GPENCIL) { + return; + } + + const bool show_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0; + const bool show_grid = (v3d->gp_flag & V3D_GP_SHOW_GRID) != 0 && + ((ts->gpencil_v3d_align & + (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) == 0); + const bool grid_xray = (v3d->gp_flag & V3D_GP_SHOW_GRID_XRAY); + + if (show_grid && show_overlays) { + const char *grid_unit = nullptr; + float mat[4][4]; + float col_grid[4]; + float size[2]; + + /* set color */ + copy_v3_v3(col_grid, gpd->grid.color); + col_grid[3] = max_ff(v3d->overlay.gpencil_grid_opacity, 0.01f); + + copy_m4_m4(mat, ob->obmat); + + /* Rotate and scale except align to cursor. */ + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); + if (gpl != nullptr) { + if (ts->gp_sculpt.lock_axis != GP_LOCKAXIS_CURSOR) { + float matrot[3][3]; + copy_m3_m4(matrot, gpl->layer_mat); + mul_m4_m4m3(mat, mat, matrot); + } + } + + float viewinv[4][4]; + /* Set the grid in the selected axis */ + switch (ts->gp_sculpt.lock_axis) { + case GP_LOCKAXIS_X: + swap_v4_v4(mat[0], mat[2]); + break; + case GP_LOCKAXIS_Y: + swap_v4_v4(mat[1], mat[2]); + break; + case GP_LOCKAXIS_Z: + /* Default. */ + break; + case GP_LOCKAXIS_CURSOR: { + const float3 size_vec = {1.0f, 1.0f, 1.0f}; + loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, size_vec); + break; + } + case GP_LOCKAXIS_VIEW: + /* view aligned */ + DRW_view_viewmat_get(nullptr, viewinv, true); + copy_v3_v3(mat[0], viewinv[0]); + copy_v3_v3(mat[1], viewinv[1]); + break; + } + + /* Move the grid to the right location depending of the align type. + * This is required only for 3D Cursor or Origin. */ + if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) { + copy_v3_v3(mat[3], cursor->location); + } + else if (ts->gpencil_v3d_align & GP_PROJECT_VIEWSPACE) { + copy_v3_v3(mat[3], ob->obmat[3]); + } + + translate_m4(mat, gpd->grid.offset[0], gpd->grid.offset[1], 0.0f); + mul_v2_v2fl(size, gpd->grid.scale, 2.0f * ED_scene_grid_scale(scene, &grid_unit)); + const float3 scale_vec = {size[0], size[1], 0.0f}; + rescale_m4(mat, scale_vec); + + /* Apply layer loc transform, except cursor mode. */ + if ((gpl != nullptr) && (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { + add_v3_v3(mat[3], gpl->layer_mat[3]); + } + + const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines; + const int line_count = gridlines * 4 + 2; + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; + state |= (grid_xray) ? DRW_STATE_DEPTH_ALWAYS : DRW_STATE_DEPTH_LESS_EQUAL; + + DRW_PASS_CREATE(psl->gpencil_canvas_ps, state); + + sh = OVERLAY_shader_gpencil_canvas(); + grp = DRW_shgroup_create(sh, psl->gpencil_canvas_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_vec4_copy(grp, "color", col_grid); + DRW_shgroup_uniform_vec3_copy(grp, "xAxis", mat[0]); + DRW_shgroup_uniform_vec3_copy(grp, "yAxis", mat[1]); + DRW_shgroup_uniform_vec3_copy(grp, "origin", mat[3]); + DRW_shgroup_uniform_int_copy(grp, "halfLineCount", line_count / 2); + DRW_shgroup_call_procedural_lines(grp, nullptr, line_count); + } +} + +static void OVERLAY_edit_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + bGPdata *gpd = (bGPdata *)ob->data; + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + + /* Overlay is only for active object. */ + if (ob != draw_ctx->obact) { + return; + } + + if (pd->edit_gpencil_wires_grp) { + DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_wires_grp); + DRW_shgroup_uniform_vec4_copy(grp, "gpEditColor", gpd->line_color); + + struct GPUBatch *geom = DRW_cache_gpencil_edit_lines_get(ob, pd->cfra); + DRW_shgroup_call_no_cull(pd->edit_gpencil_wires_grp, geom, ob); + } + + if (pd->edit_gpencil_points_grp) { + const bool show_direction = (v3d->gp_flag & V3D_GP_SHOW_STROKE_DIRECTION) != 0; + + DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_points_grp); + DRW_shgroup_uniform_float_copy(grp, "doStrokeEndpoints", show_direction); + + struct GPUBatch *geom = DRW_cache_gpencil_edit_points_get(ob, pd->cfra); + DRW_shgroup_call_no_cull(grp, geom, ob); + } + + if (pd->edit_gpencil_curve_handle_grp) { + struct GPUBatch *geom = DRW_cache_gpencil_edit_curve_handles_get(ob, pd->cfra); + if (geom) { + DRW_shgroup_call_no_cull(pd->edit_gpencil_curve_handle_grp, geom, ob); + } + } + + if (pd->edit_gpencil_curve_points_grp) { + struct GPUBatch *geom = DRW_cache_gpencil_edit_curve_points_get(ob, pd->cfra); + if (geom) { + DRW_shgroup_call_no_cull(pd->edit_gpencil_curve_points_grp, geom, ob); + } + } +} + +static void overlay_gpencil_draw_stroke_color_name(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) +{ + Object *ob = (Object *)thunk; + Material *ma = BKE_object_material_get_eval(ob, gps->mat_nr + 1); + if (ma == nullptr) { + return; + } + MaterialGPencilStyle *gp_style = ma->gp_style; + /* skip stroke if it doesn't have any valid data */ + if ((gps->points == nullptr) || (gps->totpoints < 1) || (gp_style == nullptr)) { + return; + } + /* check if the color is visible */ + if (gp_style->flag & GP_MATERIAL_HIDE) { + return; + } + /* only if selected */ + if (gps->flag & GP_STROKE_SELECT) { + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + /* Draw name at the first selected point. */ + if (pt->flag & GP_SPOINT_SELECT) { + 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, nullptr); + uchar color[4]; + UI_GetThemeColor4ubv(theme_id, color); + + float fpt[3]; + mul_v3_m4v3(fpt, ob->obmat, &pt->x); + + struct DRWTextStore *dt = DRW_text_cache_ensure(); + 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; + } + } + } +} + +static void OVERLAY_gpencil_color_names(Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + int cfra = DEG_get_ctime(draw_ctx->depsgraph); + + BKE_gpencil_visible_stroke_advanced_iter( + nullptr, ob, nullptr, overlay_gpencil_draw_stroke_color_name, ob, false, cfra); +} + +void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + + bGPdata *gpd = (bGPdata *)ob->data; + if (gpd == nullptr) { + return; + } + + if (GPENCIL_ANY_MODE(gpd)) { + OVERLAY_edit_gpencil_cache_populate(vedata, ob); + } + + /* don't show object extras in set's */ + if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) { + if ((v3d->gp_flag & V3D_GP_SHOW_MATERIAL_NAME) && (ob->mode == OB_MODE_EDIT_GPENCIL) && + DRW_state_show_text()) { + OVERLAY_gpencil_color_names(ob); + } + } +} + +void OVERLAY_gpencil_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + if (psl->gpencil_canvas_ps) { + DRW_draw_pass(psl->gpencil_canvas_ps); + } +} + +void OVERLAY_edit_gpencil_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + if (psl->edit_gpencil_gizmos_ps) { + DRW_draw_pass(psl->edit_gpencil_gizmos_ps); + } + + if (psl->edit_gpencil_ps) { + DRW_draw_pass(psl->edit_gpencil_ps); + } + + /* Curve edit handles. */ + if (psl->edit_gpencil_curve_ps) { + DRW_draw_pass(psl->edit_gpencil_curve_ps); + } +} diff --git a/source/blender/draw/engines/overlay/overlay_grid.c b/source/blender/draw/engines/overlay/overlay_grid.c deleted file mode 100644 index e424f49455b..00000000000 --- a/source/blender/draw/engines/overlay/overlay_grid.c +++ /dev/null @@ -1,306 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "DRW_render.h" - -#include "DNA_camera_types.h" -#include "DNA_screen_types.h" - -#include "DEG_depsgraph_query.h" - -#include "ED_image.h" -#include "ED_view3d.h" - -#include "UI_resources.h" - -#include "overlay_private.h" - -BLI_STATIC_ASSERT(SI_GRID_STEPS_LEN == OVERLAY_GRID_STEPS_LEN, "") - -void OVERLAY_grid_init(OVERLAY_Data *vedata) -{ - OVERLAY_PrivateData *pd = vedata->stl->pd; - OVERLAY_GridData *grid = &pd->grid_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - float *grid_axes = pd->grid.grid_axes; - float *zplane_axes = pd->grid.zplane_axes; - float grid_steps[SI_GRID_STEPS_LEN] = { - 0.001f, 0.01f, 0.1f, 1.0f, 10.0f, 100.0f, 1000.0f, 10000.0f}; - OVERLAY_GridBits grid_flag = 0, zneg_flag = 0, zpos_flag = 0; - grid->line_size = max_ff(0.0f, U.pixelsize - 1.0f) * 0.5f; - /* Default, nothing is drawn. */ - pd->grid.grid_flag = pd->grid.zneg_flag = pd->grid.zpos_flag = 0; - - if (pd->space_type == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; - View2D *v2d = &draw_ctx->region->v2d; - - /* Only UV Edit mode has the various Overlay options for now. */ - const bool is_uv_edit = sima->mode == SI_MODE_UV; - - const bool background_enabled = is_uv_edit ? (!pd->hide_overlays && - (sima->overlay.flag & - SI_OVERLAY_SHOW_GRID_BACKGROUND) != 0) : - true; - if (background_enabled) { - grid_flag = GRID_BACK | PLANE_IMAGE; - } - - const bool draw_grid = is_uv_edit || !ED_space_image_has_buffer(sima); - if (background_enabled && draw_grid) { - grid_flag |= SHOW_GRID; - if (is_uv_edit && (sima->flag & SI_CUSTOM_GRID) != 0) { - grid_flag |= CUSTOM_GRID; - } - } - - grid->distance = 1.0f; - copy_v3_fl3(grid->size, 1.0f, 1.0f, 1.0f); - if (is_uv_edit) { - grid->size[0] = (float)sima->tile_grid_shape[0]; - grid->size[1] = (float)sima->tile_grid_shape[1]; - } - - grid->zoom_factor = ED_space_image_zoom_level(v2d, SI_GRID_STEPS_LEN); - ED_space_image_grid_steps(sima, grid_steps, SI_GRID_STEPS_LEN); - } - else { - /* SPACE_VIEW3D */ - 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; - - if (pd->hide_overlays || !(pd->v3d_gridflag & (V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z | - V3D_SHOW_FLOOR | V3D_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 perspective view or non-axis aligned view. */ - if (winmat[3][3] == 0.0f || rv3d->view == RV3D_VIEW_USER) { - if (show_axis_x) { - grid_flag |= PLANE_XY | SHOW_AXIS_X; - } - if (show_axis_y) { - grid_flag |= PLANE_XY | SHOW_AXIS_Y; - } - if (show_floor) { - grid_flag |= PLANE_XY | SHOW_GRID; - } - } - else { - if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) { - 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)) { - 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)) { - grid_flag = PLANE_XZ | SHOW_AXIS_X | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK; - } - } - - grid_axes[0] = (float)((grid_flag & (PLANE_XZ | PLANE_XY)) != 0); - grid_axes[1] = (float)((grid_flag & (PLANE_YZ | PLANE_XY)) != 0); - grid_axes[2] = (float)((grid_flag & (PLANE_YZ | PLANE_XZ)) != 0); - - /* Z axis if needed */ - if (((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) && show_axis_z) { - 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])) { - zpos_flag |= PLANE_XZ; - } - else { - zpos_flag |= PLANE_YZ; - } - - zneg_flag = 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))) { - zpos_flag |= CLIP_ZPOS; - zneg_flag |= CLIP_ZNEG; - } - else { - zpos_flag |= CLIP_ZNEG; - zneg_flag |= CLIP_ZPOS; - } - - zplane_axes[0] = (float)((zpos_flag & (PLANE_XZ | PLANE_XY)) != 0); - zplane_axes[1] = (float)((zpos_flag & (PLANE_YZ | PLANE_XY)) != 0); - zplane_axes[2] = (float)((zpos_flag & (PLANE_YZ | PLANE_XZ)) != 0); - } - else { - zneg_flag = 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; - grid_flag |= GRID_CAMERA; - zneg_flag |= GRID_CAMERA; - zpos_flag |= GRID_CAMERA; - } - else { - dist = v3d->clip_end; - } - - if (winmat[3][3] == 0.0f) { - copy_v3_fl(grid->size, dist); - } - else { - float viewdist = 1.0f / min_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1])); - copy_v3_fl(grid->size, viewdist * dist); - } - - grid->distance = dist / 2.0f; - - ED_view3d_grid_steps(scene, v3d, rv3d, grid_steps); - - if ((v3d->flag & (V3D_XR_SESSION_SURFACE | V3D_XR_SESSION_MIRROR)) != 0) { - /* The calculations for the grid parameters assume that the view matrix has no scale - * component, which may not be correct if the user is "shrunk" or "enlarged" by zooming in or - * out. Therefore, we need to compensate the values here. */ - /* Assumption is uniform scaling (all column vectors are of same length). */ - float viewinvscale = len_v3(viewinv[0]); - grid->distance *= viewinvscale; - } - } - - /* Convert to UBO alignment. */ - for (int i = 0; i < SI_GRID_STEPS_LEN; i++) { - grid->steps[i][0] = grid_steps[i]; - } - pd->grid.grid_flag = grid_flag; - pd->grid.zneg_flag = zneg_flag; - pd->grid.zpos_flag = zpos_flag; -} - -void OVERLAY_grid_cache_init(OVERLAY_Data *ved) -{ - OVERLAY_StorageList *stl = ved->stl; - OVERLAY_PrivateData *pd = stl->pd; - OVERLAY_GridData *grid = &pd->grid_data; - - OVERLAY_PassList *psl = ved->psl; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - - psl->grid_ps = NULL; - - if ((pd->grid.grid_flag == 0 && pd->grid.zpos_flag == 0) || !DRW_state_is_fbo()) { - return; - } - - if (ved->instance->grid_ubo == NULL) { - ved->instance->grid_ubo = GPU_uniformbuf_create(sizeof(OVERLAY_GridData)); - } - GPU_uniformbuf_update(ved->instance->grid_ubo, &pd->grid_data); - - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; - DRW_PASS_CREATE(psl->grid_ps, state); - - if (pd->space_type == SPACE_IMAGE) { - float mat[4][4]; - - /* Add quad background. */ - GPUShader *sh = OVERLAY_shader_grid_background(); - DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->grid_ps); - float color_back[4]; - interp_v4_v4v4(color_back, G_draw.block.color_background, G_draw.block.color_grid, 0.5); - DRW_shgroup_uniform_vec4_copy(grp, "color", color_back); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - unit_m4(mat); - mat[0][0] = grid->size[0]; - mat[1][1] = grid->size[1]; - mat[2][2] = grid->size[2]; - DRW_shgroup_call_obmat(grp, DRW_cache_quad_get(), mat); - } - - { - DRWShadingGroup *grp; - struct GPUBatch *geom = DRW_cache_grid_get(); - - GPUShader *sh = OVERLAY_shader_grid(); - - /* Create 3 quads to render ordered transparency Z axis */ - grp = DRW_shgroup_create(sh, psl->grid_ps); - DRW_shgroup_uniform_block(grp, "grid_buf", ved->instance->grid_ubo); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &dtxl->depth); - - DRW_shgroup_uniform_int_copy(grp, "grid_flag", pd->grid.zneg_flag); - DRW_shgroup_uniform_vec3_copy(grp, "plane_axes", pd->grid.zplane_axes); - if (pd->grid.zneg_flag & SHOW_AXIS_Z) { - DRW_shgroup_call(grp, geom, NULL); - } - - grp = DRW_shgroup_create_sub(grp); - DRW_shgroup_uniform_int_copy(grp, "grid_flag", pd->grid.grid_flag); - DRW_shgroup_uniform_vec3_copy(grp, "plane_axes", pd->grid.grid_axes); - if (pd->grid.grid_flag) { - DRW_shgroup_call(grp, geom, NULL); - } - - grp = DRW_shgroup_create_sub(grp); - DRW_shgroup_uniform_int_copy(grp, "grid_flag", pd->grid.zpos_flag); - DRW_shgroup_uniform_vec3_copy(grp, "plane_axes", pd->grid.zplane_axes); - if (pd->grid.zpos_flag & SHOW_AXIS_Z) { - DRW_shgroup_call(grp, geom, NULL); - } - } - - if (pd->space_type == SPACE_IMAGE) { - float theme_color[4]; - UI_GetThemeColorShade4fv(TH_BACK, 60, theme_color); - srgb_to_linearrgb_v4(theme_color, theme_color); - - float mat[4][4]; - /* add wire border */ - GPUShader *sh = OVERLAY_shader_grid_image(); - DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->grid_ps); - DRW_shgroup_uniform_vec4_copy(grp, "color", theme_color); - unit_m4(mat); - for (int x = 0; x < grid->size[0]; x++) { - mat[3][0] = x; - for (int y = 0; y < grid->size[1]; y++) { - mat[3][1] = y; - DRW_shgroup_call_obmat(grp, DRW_cache_quad_wires_get(), mat); - } - } - } -} - -void OVERLAY_grid_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - if (psl->grid_ps) { - DRW_draw_pass(psl->grid_ps); - } -} diff --git a/source/blender/draw/engines/overlay/overlay_grid.cc b/source/blender/draw/engines/overlay/overlay_grid.cc new file mode 100644 index 00000000000..71abcf91223 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_grid.cc @@ -0,0 +1,307 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "DNA_camera_types.h" +#include "DNA_screen_types.h" + +#include "DEG_depsgraph_query.h" + +#include "ED_image.h" +#include "ED_view3d.h" + +#include "UI_resources.h" + +#include "overlay_private.hh" + +BLI_STATIC_ASSERT(SI_GRID_STEPS_LEN == OVERLAY_GRID_STEPS_LEN, "") + +void OVERLAY_grid_init(OVERLAY_Data *vedata) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + OVERLAY_GridData *grid = &pd->grid_data; + const DRWContextState *draw_ctx = DRW_context_state_get(); + + float *grid_axes = pd->grid.grid_axes; + float *zplane_axes = pd->grid.zplane_axes; + float grid_steps[SI_GRID_STEPS_LEN] = { + 0.001f, 0.01f, 0.1f, 1.0f, 10.0f, 100.0f, 1000.0f, 10000.0f}; + OVERLAY_GridBits grid_flag = OVERLAY_GridBits(0), zneg_flag = OVERLAY_GridBits(0), + zpos_flag = OVERLAY_GridBits(0); + grid->line_size = max_ff(0.0f, U.pixelsize - 1.0f) * 0.5f; + /* Default, nothing is drawn. */ + pd->grid.grid_flag = pd->grid.zneg_flag = pd->grid.zpos_flag = OVERLAY_GridBits(0); + + if (pd->space_type == SPACE_IMAGE) { + SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; + View2D *v2d = &draw_ctx->region->v2d; + + /* Only UV Edit mode has the various Overlay options for now. */ + const bool is_uv_edit = sima->mode == SI_MODE_UV; + + const bool background_enabled = is_uv_edit ? (!pd->hide_overlays && + (sima->overlay.flag & + SI_OVERLAY_SHOW_GRID_BACKGROUND) != 0) : + true; + if (background_enabled) { + grid_flag = GRID_BACK | PLANE_IMAGE; + } + + const bool draw_grid = is_uv_edit || !ED_space_image_has_buffer(sima); + if (background_enabled && draw_grid) { + grid_flag |= SHOW_GRID; + if (is_uv_edit && (sima->flag & SI_CUSTOM_GRID) != 0) { + grid_flag |= CUSTOM_GRID; + } + } + + grid->distance = 1.0f; + copy_v3_fl3(grid->size, 1.0f, 1.0f, 1.0f); + if (is_uv_edit) { + grid->size[0] = (float)sima->tile_grid_shape[0]; + grid->size[1] = (float)sima->tile_grid_shape[1]; + } + + grid->zoom_factor = ED_space_image_zoom_level(v2d, SI_GRID_STEPS_LEN); + ED_space_image_grid_steps(sima, grid_steps, SI_GRID_STEPS_LEN); + } + else { + /* SPACE_VIEW3D */ + 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; + + if (pd->hide_overlays || !(pd->v3d_gridflag & (V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z | + V3D_SHOW_FLOOR | V3D_SHOW_ORTHO_GRID))) { + return; + } + + float viewinv[4][4], wininv[4][4]; + float viewmat[4][4], winmat[4][4]; + DRW_view_winmat_get(nullptr, winmat, false); + DRW_view_winmat_get(nullptr, wininv, true); + DRW_view_viewmat_get(nullptr, viewmat, false); + DRW_view_viewmat_get(nullptr, viewinv, true); + + /* If perspective view or non-axis aligned view. */ + if (winmat[3][3] == 0.0f || rv3d->view == RV3D_VIEW_USER) { + if (show_axis_x) { + grid_flag |= PLANE_XY | SHOW_AXIS_X; + } + if (show_axis_y) { + grid_flag |= PLANE_XY | SHOW_AXIS_Y; + } + if (show_floor) { + grid_flag |= PLANE_XY | SHOW_GRID; + } + } + else { + if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) { + 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)) { + 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)) { + grid_flag = PLANE_XZ | SHOW_AXIS_X | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK; + } + } + + grid_axes[0] = (float)((grid_flag & (PLANE_XZ | PLANE_XY)) != 0); + grid_axes[1] = (float)((grid_flag & (PLANE_YZ | PLANE_XY)) != 0); + grid_axes[2] = (float)((grid_flag & (PLANE_YZ | PLANE_XZ)) != 0); + + /* Z axis if needed */ + if (((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) && show_axis_z) { + 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])) { + zpos_flag |= PLANE_XZ; + } + else { + zpos_flag |= PLANE_YZ; + } + + zneg_flag = 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))) { + zpos_flag |= CLIP_ZPOS; + zneg_flag |= CLIP_ZNEG; + } + else { + zpos_flag |= CLIP_ZNEG; + zneg_flag |= CLIP_ZPOS; + } + + zplane_axes[0] = (float)((zpos_flag & (PLANE_XZ | PLANE_XY)) != 0); + zplane_axes[1] = (float)((zpos_flag & (PLANE_YZ | PLANE_XY)) != 0); + zplane_axes[2] = (float)((zpos_flag & (PLANE_YZ | PLANE_XZ)) != 0); + } + else { + zneg_flag = 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; + grid_flag |= GRID_CAMERA; + zneg_flag |= GRID_CAMERA; + zpos_flag |= GRID_CAMERA; + } + else { + dist = v3d->clip_end; + } + + if (winmat[3][3] == 0.0f) { + copy_v3_fl(grid->size, dist); + } + else { + float viewdist = 1.0f / min_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1])); + copy_v3_fl(grid->size, viewdist * dist); + } + + grid->distance = dist / 2.0f; + + ED_view3d_grid_steps(scene, v3d, rv3d, grid_steps); + + if ((v3d->flag & (V3D_XR_SESSION_SURFACE | V3D_XR_SESSION_MIRROR)) != 0) { + /* The calculations for the grid parameters assume that the view matrix has no scale + * component, which may not be correct if the user is "shrunk" or "enlarged" by zooming in or + * out. Therefore, we need to compensate the values here. */ + /* Assumption is uniform scaling (all column vectors are of same length). */ + float viewinvscale = len_v3(viewinv[0]); + grid->distance *= viewinvscale; + } + } + + /* Convert to UBO alignment. */ + for (int i = 0; i < SI_GRID_STEPS_LEN; i++) { + grid->steps[i][0] = grid_steps[i]; + } + pd->grid.grid_flag = grid_flag; + pd->grid.zneg_flag = zneg_flag; + pd->grid.zpos_flag = zpos_flag; +} + +void OVERLAY_grid_cache_init(OVERLAY_Data *ved) +{ + OVERLAY_StorageList *stl = ved->stl; + OVERLAY_PrivateData *pd = stl->pd; + OVERLAY_GridData *grid = &pd->grid_data; + + OVERLAY_PassList *psl = ved->psl; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + psl->grid_ps = nullptr; + + if ((pd->grid.grid_flag == 0 && pd->grid.zpos_flag == 0) || !DRW_state_is_fbo()) { + return; + } + + if (ved->instance->grid_ubo == nullptr) { + ved->instance->grid_ubo = GPU_uniformbuf_create(sizeof(OVERLAY_GridData)); + } + GPU_uniformbuf_update(ved->instance->grid_ubo, &pd->grid_data); + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->grid_ps, state); + + if (pd->space_type == SPACE_IMAGE) { + float mat[4][4]; + + /* Add quad background. */ + GPUShader *sh = OVERLAY_shader_grid_background(); + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->grid_ps); + float color_back[4]; + interp_v4_v4v4(color_back, G_draw.block.color_background, G_draw.block.color_grid, 0.5); + DRW_shgroup_uniform_vec4_copy(grp, "color", color_back); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); + unit_m4(mat); + mat[0][0] = grid->size[0]; + mat[1][1] = grid->size[1]; + mat[2][2] = grid->size[2]; + DRW_shgroup_call_obmat(grp, DRW_cache_quad_get(), mat); + } + + { + DRWShadingGroup *grp; + struct GPUBatch *geom = DRW_cache_grid_get(); + + GPUShader *sh = OVERLAY_shader_grid(); + + /* Create 3 quads to render ordered transparency Z axis */ + grp = DRW_shgroup_create(sh, psl->grid_ps); + DRW_shgroup_uniform_block(grp, "grid_buf", ved->instance->grid_ubo); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &dtxl->depth); + + DRW_shgroup_uniform_int_copy(grp, "grid_flag", pd->grid.zneg_flag); + DRW_shgroup_uniform_vec3_copy(grp, "plane_axes", pd->grid.zplane_axes); + if (pd->grid.zneg_flag & SHOW_AXIS_Z) { + DRW_shgroup_call(grp, geom, nullptr); + } + + grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_uniform_int_copy(grp, "grid_flag", pd->grid.grid_flag); + DRW_shgroup_uniform_vec3_copy(grp, "plane_axes", pd->grid.grid_axes); + if (pd->grid.grid_flag) { + DRW_shgroup_call(grp, geom, nullptr); + } + + grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_uniform_int_copy(grp, "grid_flag", pd->grid.zpos_flag); + DRW_shgroup_uniform_vec3_copy(grp, "plane_axes", pd->grid.zplane_axes); + if (pd->grid.zpos_flag & SHOW_AXIS_Z) { + DRW_shgroup_call(grp, geom, nullptr); + } + } + + if (pd->space_type == SPACE_IMAGE) { + float theme_color[4]; + UI_GetThemeColorShade4fv(TH_BACK, 60, theme_color); + srgb_to_linearrgb_v4(theme_color, theme_color); + + float mat[4][4]; + /* add wire border */ + GPUShader *sh = OVERLAY_shader_grid_image(); + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->grid_ps); + DRW_shgroup_uniform_vec4_copy(grp, "color", theme_color); + unit_m4(mat); + for (int x = 0; x < grid->size[0]; x++) { + mat[3][0] = x; + for (int y = 0; y < grid->size[1]; y++) { + mat[3][1] = y; + DRW_shgroup_call_obmat(grp, DRW_cache_quad_wires_get(), mat); + } + } + } +} + +void OVERLAY_grid_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + if (psl->grid_ps) { + DRW_draw_pass(psl->grid_ps); + } +} diff --git a/source/blender/draw/engines/overlay/overlay_image.c b/source/blender/draw/engines/overlay/overlay_image.c deleted file mode 100644 index 3e9c05bb59f..00000000000 --- a/source/blender/draw/engines/overlay/overlay_image.c +++ /dev/null @@ -1,498 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * 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 "BLI_listbase.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; - - DRWView *default_view = (DRWView *)DRW_view_default_get(); - pd->view_reference_images = DRW_view_create_with_zoffset(default_view, 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_PREMUL; - DRW_PASS_CREATE(psl->image_background_ps, state); - state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_UNDER_PREMUL; - DRW_PASS_CREATE(psl->image_background_scene_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_PREMUL; - 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_PREMUL; - DRW_PASS_CREATE(psl->image_empties_front_ps, state); - DRW_PASS_CREATE(psl->image_foreground_ps, state); - DRW_PASS_CREATE(psl->image_foreground_scene_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 eStereoViews camera_background_images_stereo_eye(const Scene *scene, const View3D *v3d) -{ - if ((scene->r.scemode & R_MULTIVIEW) == 0) { - return STEREO_LEFT_ID; - } - if (v3d->stereo3d_camera != STEREO_3D_ID) { - /* show only left or right camera */ - return v3d->stereo3d_camera; - } - - return v3d->multiview_eye; -} - -static void camera_background_images_stereo_setup(const Scene *scene, - const View3D *v3d, - Image *ima, - ImageUser *iuser) -{ - if (BKE_image_is_stereo(ima)) { - iuser->flag |= IMA_SHOW_STEREO; - iuser->multiview_eye = camera_background_images_stereo_eye(scene, v3d); - 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, - bool *r_use_view_transform) -{ - void *lock; - 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; - *r_use_view_transform = false; - - switch (bgpic->source) { - case CAM_BGIMG_SOURCE_IMAGE: - if (image == NULL) { - return NULL; - } - *r_use_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL); - *r_use_view_transform = (image->flag & IMA_VIEW_AS_RENDER) != 0; - - 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, don't show. */ - return NULL; - } - - camera_background_images_stereo_setup(scene, draw_ctx->v3d, image, iuser); - - iuser->scene = draw_ctx->scene; - ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, &lock); - if (ibuf == NULL) { - BKE_image_release_ibuf(image, ibuf, lock); - iuser->scene = NULL; - return NULL; - } - width = ibuf->x; - height = ibuf->y; - tex = BKE_image_get_gpu_texture(image, iuser, ibuf); - BKE_image_release_ibuf(image, ibuf, lock); - iuser->scene = NULL; - - if (tex == NULL) { - return NULL; - } - - aspect_x = bgpic->ima->aspx; - aspect_y = bgpic->ima->aspy; - 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 = BKE_movieclip_get_gpu_texture(clip, &bgpic->cuser); - if (tex == NULL) { - return NULL; - } - - aspect_x = clip->aspx; - aspect_y = clip->aspy; - *r_use_view_transform = true; - - 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; - BKE_movieclip_free_gputexture(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]; - if (cam->type == CAM_ORTHO) { - mul_v2_fl(translate[3], cam->ortho_scale); - } - /* 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(); - const View3D *v3d = draw_ctx->v3d; - const Scene *scene = draw_ctx->scene; - 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; - } - - const bool stereo_eye = camera_background_images_stereo_eye(scene, v3d) == STEREO_LEFT_ID; - const char *viewname = (stereo_eye == STEREO_LEFT_ID) ? STEREO_RIGHT_NAME : STEREO_LEFT_NAME; - float modelmat[4][4]; - BKE_camera_multiview_model_matrix(&scene->r, ob, viewname, modelmat); - - LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) { - if (bgpic->flag & CAM_BGIMG_FLAG_DISABLED) { - continue; - } - - float aspect = 1.0; - bool use_alpha_premult; - bool use_view_transform = false; - 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, &use_view_transform); - - if (tex) { - image_camera_background_matrix_get(cam, bgpic, draw_ctx, aspect, mat); - - const bool is_foreground = (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != 0; - /* Alpha is clamped just below 1.0 to fix background images to interfere with foreground - * images. Without this a background image with 1.0 will be rendered on top of a transparent - * foreground image due to the different blending modes they use. */ - const float color_premult_alpha[4] = {1.0f, 1.0f, 1.0f, MIN2(bgpic->alpha, 0.999999)}; - - DRWPass *pass = is_foreground ? (use_view_transform ? psl->image_foreground_scene_ps : - psl->image_foreground_ps) : - (use_view_transform ? psl->image_background_scene_ps : - psl->image_background_ps); - - 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", true); - DRW_shgroup_uniform_bool_copy(grp, "isCameraBackground", true); - DRW_shgroup_uniform_bool_copy(grp, "depthSet", true); - DRW_shgroup_uniform_vec4_copy(grp, "color", color_premult_alpha); - 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) { - ImageUser iuser = *ob->iuser; - camera_background_images_stereo_setup(draw_ctx->scene, draw_ctx->v3d, ima, &iuser); - tex = BKE_image_get_gpu_texture(ima, &iuser, NULL); - 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; - if ((ob->dtx & OB_DRAW_IN_FRONT) != 0) { - /* Object In Front overrides image empty depth mode. */ - pass = psl->image_empties_front_ps; - } - else { - 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, "isCameraBackground", 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_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_scene_background_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - if (DRW_state_is_fbo() && (!DRW_pass_is_empty(psl->image_background_scene_ps) || - !DRW_pass_is_empty(psl->image_foreground_scene_ps))) { - const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - GPU_framebuffer_bind(dfbl->default_fb); - - DRW_draw_pass(psl->image_background_scene_ps); - DRW_draw_pass(psl->image_foreground_scene_ps); - } -} - -void OVERLAY_image_background_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - DRW_draw_pass(psl->image_background_ps); - DRW_draw_pass(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_empties_ps); - DRW_draw_pass(psl->image_empties_blend_ps); - - DRW_view_set_active(NULL); -} - -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(NULL); - - OVERLAY_image_free_movieclips_textures(vedata); -} diff --git a/source/blender/draw/engines/overlay/overlay_image.cc b/source/blender/draw/engines/overlay/overlay_image.cc new file mode 100644 index 00000000000..dff30eed620 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_image.cc @@ -0,0 +1,500 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * 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 "BLI_listbase.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.hh" + +void OVERLAY_image_init(OVERLAY_Data *vedata) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_PrivateData *pd = vedata->stl->pd; + + DRWView *default_view = (DRWView *)DRW_view_default_get(); + pd->view_reference_images = DRW_view_create_with_zoffset(default_view, 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_PREMUL; + DRW_PASS_CREATE(psl->image_background_ps, state); + state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_UNDER_PREMUL; + DRW_PASS_CREATE(psl->image_background_scene_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_PREMUL; + 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_PREMUL; + DRW_PASS_CREATE(psl->image_empties_front_ps, state); + DRW_PASS_CREATE(psl->image_foreground_ps, state); + DRW_PASS_CREATE(psl->image_foreground_scene_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 eStereoViews camera_background_images_stereo_eye(const Scene *scene, const View3D *v3d) +{ + if ((scene->r.scemode & R_MULTIVIEW) == 0) { + return STEREO_LEFT_ID; + } + if (v3d->stereo3d_camera != STEREO_3D_ID) { + /* show only left or right camera */ + return eStereoViews(v3d->stereo3d_camera); + } + + return eStereoViews(v3d->multiview_eye); +} + +static void camera_background_images_stereo_setup(const Scene *scene, + const View3D *v3d, + Image *ima, + ImageUser *iuser) +{ + if (BKE_image_is_stereo(ima)) { + iuser->flag |= IMA_SHOW_STEREO; + iuser->multiview_eye = camera_background_images_stereo_eye(scene, v3d); + 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, + bool *r_use_view_transform) +{ + void *lock; + Image *image = bgpic->ima; + ImageUser *iuser = &bgpic->iuser; + MovieClip *clip = nullptr; + GPUTexture *tex = nullptr; + 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; + *r_use_view_transform = false; + + switch (bgpic->source) { + case CAM_BGIMG_SOURCE_IMAGE: { + if (image == nullptr) { + return nullptr; + } + *r_use_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL); + *r_use_view_transform = (image->flag & IMA_VIEW_AS_RENDER) != 0; + + 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, don't show. */ + return nullptr; + } + + camera_background_images_stereo_setup(scene, draw_ctx->v3d, image, iuser); + + iuser->scene = draw_ctx->scene; + ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, &lock); + if (ibuf == nullptr) { + BKE_image_release_ibuf(image, ibuf, lock); + iuser->scene = nullptr; + return nullptr; + } + width = ibuf->x; + height = ibuf->y; + tex = BKE_image_get_gpu_texture(image, iuser, ibuf); + BKE_image_release_ibuf(image, ibuf, lock); + iuser->scene = nullptr; + + if (tex == nullptr) { + return nullptr; + } + + aspect_x = bgpic->ima->aspx; + aspect_y = bgpic->ima->aspy; + 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 == nullptr) { + return nullptr; + } + + BKE_movieclip_user_set_frame(&bgpic->cuser, ctime); + tex = BKE_movieclip_get_gpu_texture(clip, &bgpic->cuser); + if (tex == nullptr) { + return nullptr; + } + + aspect_x = clip->aspx; + aspect_y = clip->aspy; + *r_use_view_transform = true; + + 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 nullptr; + } + + *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 = static_cast(BLI_pophead(&data->stl->pd->bg_movie_clips)))) { + MovieClip *clip = (MovieClip *)link->data; + BKE_movieclip_free_gputexture(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]; + if (cam->type == CAM_ORTHO) { + mul_v2_fl(translate[3], cam->ortho_scale); + } + /* 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(); + const View3D *v3d = draw_ctx->v3d; + const Scene *scene = draw_ctx->scene; + Camera *cam = static_cast(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; + } + + const bool stereo_eye = camera_background_images_stereo_eye(scene, v3d) == STEREO_LEFT_ID; + const char *viewname = (stereo_eye == STEREO_LEFT_ID) ? STEREO_RIGHT_NAME : STEREO_LEFT_NAME; + float modelmat[4][4]; + BKE_camera_multiview_model_matrix(&scene->r, ob, viewname, modelmat); + + LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) { + if (bgpic->flag & CAM_BGIMG_FLAG_DISABLED) { + continue; + } + + float aspect = 1.0; + bool use_alpha_premult; + bool use_view_transform = false; + 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, &use_view_transform); + + if (tex) { + image_camera_background_matrix_get(cam, bgpic, draw_ctx, aspect, mat); + + const bool is_foreground = (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != 0; + /* Alpha is clamped just below 1.0 to fix background images to interfere with foreground + * images. Without this a background image with 1.0 will be rendered on top of a transparent + * foreground image due to the different blending modes they use. */ + const float color_premult_alpha[4] = {1.0f, 1.0f, 1.0f, std::min(bgpic->alpha, 0.999999f)}; + + DRWPass *pass = is_foreground ? (use_view_transform ? psl->image_foreground_scene_ps : + psl->image_foreground_ps) : + (use_view_transform ? psl->image_background_scene_ps : + psl->image_background_ps); + + 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", true); + DRW_shgroup_uniform_bool_copy(grp, "isCameraBackground", true); + DRW_shgroup_uniform_bool_copy(grp, "depthSet", true); + DRW_shgroup_uniform_vec4_copy(grp, "color", color_premult_alpha); + 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 = nullptr; + Image *ima = static_cast(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 != nullptr) { + ImageUser iuser = *ob->iuser; + camera_background_images_stereo_setup(draw_ctx->scene, draw_ctx->v3d, ima, &iuser); + tex = BKE_image_get_gpu_texture(ima, &iuser, nullptr); + 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(ima, 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 = nullptr; + if ((ob->dtx & OB_DRAW_IN_FRONT) != 0) { + /* Object In Front overrides image empty depth mode. */ + pass = psl->image_empties_front_ps; + } + else { + 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, "isCameraBackground", 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_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_scene_background_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + if (DRW_state_is_fbo() && (!DRW_pass_is_empty(psl->image_background_scene_ps) || + !DRW_pass_is_empty(psl->image_foreground_scene_ps))) { + const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + GPU_framebuffer_bind(dfbl->default_fb); + + DRW_draw_pass(psl->image_background_scene_ps); + DRW_draw_pass(psl->image_foreground_scene_ps); + } +} + +void OVERLAY_image_background_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + DRW_draw_pass(psl->image_background_ps); + DRW_draw_pass(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_empties_ps); + DRW_draw_pass(psl->image_empties_blend_ps); + + DRW_view_set_active(nullptr); +} + +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(nullptr); + + 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 deleted file mode 100644 index 2035a9a9d3b..00000000000 --- a/source/blender/draw/engines/overlay/overlay_lattice.c +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * 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; - OVERLAY_FramebufferList *fbl = vedata->fbl; - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_default_fb); - } - - DRW_draw_pass(psl->edit_lattice_ps); -} diff --git a/source/blender/draw/engines/overlay/overlay_lattice.cc b/source/blender/draw/engines/overlay/overlay_lattice.cc new file mode 100644 index 00000000000..7b59aa78c89 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_lattice.cc @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "overlay_private.hh" + +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; + OVERLAY_FramebufferList *fbl = vedata->fbl; + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_default_fb); + } + + 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 deleted file mode 100644 index f024f5dfac8..00000000000 --- a/source/blender/draw/engines/overlay/overlay_metaball.c +++ /dev/null @@ -1,132 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * 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 wire-size. */ - 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_DRAW_IN_FRONT) != 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 = G_draw.block.color_mball_radius; - const float *col_radius_select = G_draw.block.color_mball_radius_select; - const float *col_stiffness = G_draw.block.color_mball_stiffness; - const float *col_stiffness_select = G_draw.block.color_mball_stiffness_select; - - int select_id = 0; - if (is_select) { - select_id = ob->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; - } - - /* Needed so object centers and geometry are not detected as meta-elements. */ - if (is_select) { - DRW_select_load_id(-1); - } -} - -void OVERLAY_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob) -{ - const bool do_in_front = (ob->dtx & OB_DRAW_IN_FRONT) != 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_metaball.cc b/source/blender/draw/engines/overlay/overlay_metaball.cc new file mode 100644 index 00000000000..38de273028b --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_metaball.cc @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * 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.hh" + +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 : + DRWState(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 wire-size. */ + 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_DRAW_IN_FRONT) != 0; + const bool is_select = DRW_state_is_select(); + OVERLAY_PrivateData *pd = vedata->stl->pd; + MetaBall *mb = static_cast(ob->data); + + const float *color; + const float *col_radius = G_draw.block.color_mball_radius; + const float *col_radius_select = G_draw.block.color_mball_radius_select; + const float *col_stiffness = G_draw.block.color_mball_stiffness; + const float *col_stiffness_select = G_draw.block.color_mball_stiffness_select; + + int select_id = 0; + if (is_select) { + select_id = ob->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; + } + + /* Needed so object centers and geometry are not detected as meta-elements. */ + if (is_select) { + DRW_select_load_id(-1); + } +} + +void OVERLAY_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + const bool do_in_front = (ob->dtx & OB_DRAW_IN_FRONT) != 0; + OVERLAY_PrivateData *pd = vedata->stl->pd; + MetaBall *mb = static_cast(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_mode_transfer.c b/source/blender/draw/engines/overlay/overlay_mode_transfer.c deleted file mode 100644 index e7b2008dee0..00000000000 --- a/source/blender/draw/engines/overlay/overlay_mode_transfer.c +++ /dev/null @@ -1,144 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2021 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "BKE_paint.h" -#include "DRW_render.h" - -#include "ED_view3d.h" - -#include "PIL_time.h" -#include "UI_resources.h" - -#include "overlay_private.h" - -void OVERLAY_mode_transfer_cache_init(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_PrivateData *pd = vedata->stl->pd; - - pd->mode_transfer.time = PIL_check_seconds_timer(); - - for (int i = 0; i < 2; i++) { - /* Non Meshes Pass (Camera, empties, lights ...) */ - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA; - DRW_PASS_CREATE(psl->mode_transfer_ps[i], state | pd->clipping_state); - } -} - -#define MODE_TRANSFER_FLASH_LENGTH 0.55f -/* TODO(pablodp606): Remove this option for 3.0 if fade in/out is not used. */ -#define MODE_TRANSFER_FLASH_FADE 0.0f -#define MODE_TRANSFER_FLASH_MAX_ALPHA 0.25f - -static bool mode_transfer_is_animation_running(const float anim_time) -{ - return anim_time >= 0.0f && anim_time <= MODE_TRANSFER_FLASH_LENGTH; -} - -static float mode_transfer_alpha_for_animation_time_get(const float anim_time) -{ - if (anim_time > MODE_TRANSFER_FLASH_LENGTH) { - return 0.0f; - } - - if (anim_time < 0.0f) { - return 0.0f; - } - - if (MODE_TRANSFER_FLASH_FADE <= 0.0f) { - return (1.0f - (anim_time / MODE_TRANSFER_FLASH_LENGTH)) * MODE_TRANSFER_FLASH_MAX_ALPHA; - } - - const float flash_fade_in_time = MODE_TRANSFER_FLASH_LENGTH * MODE_TRANSFER_FLASH_FADE; - const float flash_fade_out_time = MODE_TRANSFER_FLASH_LENGTH - flash_fade_in_time; - - float alpha = 0.0f; - if (anim_time < flash_fade_in_time) { - alpha = anim_time / flash_fade_in_time; - } - else { - const float fade_out_anim_time = anim_time - flash_fade_in_time; - alpha = 1.0f - (fade_out_anim_time / flash_fade_out_time); - } - - return alpha * MODE_TRANSFER_FLASH_MAX_ALPHA; -} - -void OVERLAY_mode_transfer_cache_populate(OVERLAY_Data *vedata, Object *ob) -{ - OVERLAY_PrivateData *pd = vedata->stl->pd; - OVERLAY_PassList *psl = vedata->psl; - - if (pd->xray_enabled) { - return; - } - - const float animation_time = pd->mode_transfer.time - - ob->runtime.overlay_mode_transfer_start_time; - - if (!mode_transfer_is_animation_running(animation_time)) { - return; - } - - const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; - - DRWShadingGroup *mode_transfer_grp[2]; - - for (int i = 0; i < 2; i++) { - GPUShader *sh = OVERLAY_shader_uniform_color(); - mode_transfer_grp[i] = DRW_shgroup_create(sh, psl->mode_transfer_ps[i]); - DRW_shgroup_uniform_block(mode_transfer_grp[i], "globalsBlock", G_draw.block_ubo); - - float color[4]; - UI_GetThemeColor3fv(TH_VERTEX_SELECT, color); - color[3] = mode_transfer_alpha_for_animation_time_get(animation_time); - srgb_to_linearrgb_v4(color, color); - DRW_shgroup_uniform_vec4_copy(mode_transfer_grp[i], "color", color); - } - - if (!pd->use_in_front) { - mode_transfer_grp[IN_FRONT] = mode_transfer_grp[NOT_IN_FRONT]; - } - - pd->mode_transfer.any_animated = true; - - if (use_sculpt_pbvh) { - DRW_shgroup_call_sculpt(mode_transfer_grp[is_xray], ob, false, false); - } - else { - struct GPUBatch *geom = DRW_cache_object_surface_get(ob); - if (geom) { - DRW_shgroup_call(mode_transfer_grp[is_xray], geom, ob); - } - } -} - -void OVERLAY_mode_transfer_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - DRW_draw_pass(psl->mode_transfer_ps[NOT_IN_FRONT]); -} - -void OVERLAY_mode_transfer_infront_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - DRW_draw_pass(psl->mode_transfer_ps[IN_FRONT]); -} - -void OVERLAY_mode_transfer_cache_finish(OVERLAY_Data *vedata) -{ - OVERLAY_PrivateData *pd = vedata->stl->pd; - if (pd->mode_transfer.any_animated) { - DRW_viewport_request_redraw(); - } - pd->mode_transfer.any_animated = false; -} diff --git a/source/blender/draw/engines/overlay/overlay_mode_transfer.cc b/source/blender/draw/engines/overlay/overlay_mode_transfer.cc new file mode 100644 index 00000000000..d4bc5655da3 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_mode_transfer.cc @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "BKE_paint.h" +#include "DRW_render.h" + +#include "ED_view3d.h" + +#include "PIL_time.h" +#include "UI_resources.h" + +#include "overlay_private.hh" + +void OVERLAY_mode_transfer_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + + pd->mode_transfer.time = PIL_check_seconds_timer(); + + for (int i = 0; i < 2; i++) { + /* Non Meshes Pass (Camera, empties, lights ...) */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->mode_transfer_ps[i], state | pd->clipping_state); + } +} + +#define MODE_TRANSFER_FLASH_LENGTH 0.55f +/* TODO(pablodp606): Remove this option for 3.0 if fade in/out is not used. */ +#define MODE_TRANSFER_FLASH_FADE 0.0f +#define MODE_TRANSFER_FLASH_MAX_ALPHA 0.25f + +static bool mode_transfer_is_animation_running(const float anim_time) +{ + return anim_time >= 0.0f && anim_time <= MODE_TRANSFER_FLASH_LENGTH; +} + +static float mode_transfer_alpha_for_animation_time_get(const float anim_time) +{ + if (anim_time > MODE_TRANSFER_FLASH_LENGTH) { + return 0.0f; + } + + if (anim_time < 0.0f) { + return 0.0f; + } + + if (MODE_TRANSFER_FLASH_FADE <= 0.0f) { + return (1.0f - (anim_time / MODE_TRANSFER_FLASH_LENGTH)) * MODE_TRANSFER_FLASH_MAX_ALPHA; + } + + const float flash_fade_in_time = MODE_TRANSFER_FLASH_LENGTH * MODE_TRANSFER_FLASH_FADE; + const float flash_fade_out_time = MODE_TRANSFER_FLASH_LENGTH - flash_fade_in_time; + + float alpha = 0.0f; + if (anim_time < flash_fade_in_time) { + alpha = anim_time / flash_fade_in_time; + } + else { + const float fade_out_anim_time = anim_time - flash_fade_in_time; + alpha = 1.0f - (fade_out_anim_time / flash_fade_out_time); + } + + return alpha * MODE_TRANSFER_FLASH_MAX_ALPHA; +} + +void OVERLAY_mode_transfer_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + OVERLAY_PassList *psl = vedata->psl; + + if (pd->xray_enabled) { + return; + } + + const float animation_time = pd->mode_transfer.time - + ob->runtime.overlay_mode_transfer_start_time; + + if (!mode_transfer_is_animation_running(animation_time)) { + return; + } + + const DRWContextState *draw_ctx = DRW_context_state_get(); + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + !DRW_state_is_image_render(); + const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; + + DRWShadingGroup *mode_transfer_grp[2]; + + for (int i = 0; i < 2; i++) { + GPUShader *sh = OVERLAY_shader_uniform_color(); + mode_transfer_grp[i] = DRW_shgroup_create(sh, psl->mode_transfer_ps[i]); + DRW_shgroup_uniform_block(mode_transfer_grp[i], "globalsBlock", G_draw.block_ubo); + + float color[4]; + UI_GetThemeColor3fv(TH_VERTEX_SELECT, color); + color[3] = mode_transfer_alpha_for_animation_time_get(animation_time); + srgb_to_linearrgb_v4(color, color); + DRW_shgroup_uniform_vec4_copy(mode_transfer_grp[i], "color", color); + } + + if (!pd->use_in_front) { + mode_transfer_grp[IN_FRONT] = mode_transfer_grp[NOT_IN_FRONT]; + } + + pd->mode_transfer.any_animated = true; + + if (use_sculpt_pbvh) { + DRW_shgroup_call_sculpt(mode_transfer_grp[is_xray], ob, false, false); + } + else { + struct GPUBatch *geom = DRW_cache_object_surface_get(ob); + if (geom) { + DRW_shgroup_call(mode_transfer_grp[is_xray], geom, ob); + } + } +} + +void OVERLAY_mode_transfer_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + DRW_draw_pass(psl->mode_transfer_ps[NOT_IN_FRONT]); +} + +void OVERLAY_mode_transfer_infront_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + DRW_draw_pass(psl->mode_transfer_ps[IN_FRONT]); +} + +void OVERLAY_mode_transfer_cache_finish(OVERLAY_Data *vedata) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + if (pd->mode_transfer.any_animated) { + DRW_viewport_request_redraw(); + } + pd->mode_transfer.any_animated = false; +} diff --git a/source/blender/draw/engines/overlay/overlay_motion_path.c b/source/blender/draw/engines/overlay/overlay_motion_path.c deleted file mode 100644 index 58825923f37..00000000000 --- a/source/blender/draw/engines/overlay/overlay_motion_path.c +++ /dev/null @@ -1,220 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "DRW_render.h" - -#include "BLI_listbase.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(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(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(GPU_vertbuf_get_data(mpath->points_vbo), - 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; - 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) { - const 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, NULL, mpath_batch_line_get(mpath), start_index, len); - } - - /* Draw points. */ - { - int pt_size = max_ii(mpath->line_thickness - 1, 1); - const 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, NULL, mpath_batch_points_get(mpath), start_index, len); - } - - /* Draw frame numbers at each frame-step value. */ - if (show_frame_no || (show_keyframes_no && show_keyframes)) { - int i; - uchar col[4], col_kf[4]; - /* Color Management: Exception here as texts are drawn in sRGB space directly. */ - 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_rlen(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 frame number 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_rlen(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)) { - LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { - 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_motion_path.cc b/source/blender/draw/engines/overlay/overlay_motion_path.cc new file mode 100644 index 00000000000..00b2a8665fd --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_motion_path.cc @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "BLI_listbase.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.hh" + +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(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(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(GPU_vertbuf_get_data(mpath->points_vbo), + 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), nullptr); + } + 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), nullptr); + } + 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; + 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) { + const 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, nullptr, mpath_batch_line_get(mpath), start_index, len); + } + + /* Draw points. */ + { + int pt_size = max_ii(mpath->line_thickness - 1, 1); + const 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, nullptr, mpath_batch_points_get(mpath), start_index, len); + } + + /* Draw frame numbers at each frame-step value. */ + if (show_frame_no || (show_keyframes_no && show_keyframes)) { + int i; + uchar col[4], col_kf[4]; + /* Color Management: Exception here as texts are drawn in sRGB space directly. */ + 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_rlen(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 frame number 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_rlen(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)) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + if (pchan->mpath) { + motion_path_cache(vedata, ob, pchan, &ob->pose->avs, pchan->mpath); + } + } + } + } + + if (ob->mpath) { + motion_path_cache(vedata, ob, nullptr, &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 deleted file mode 100644 index f2e2acc98a9..00000000000 --- a/source/blender/draw/engines/overlay/overlay_outline.c +++ /dev/null @@ -1,379 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "DRW_render.h" - -#include "BKE_global.h" -#include "BKE_gpencil.h" - -#include "BKE_object.h" - -#include "DNA_gpencil_types.h" - -#include "UI_resources.h" - -#include "overlay_private.h" - -/* Returns the normal plane in NDC space. */ -static void gpencil_depth_plane(Object *ob, float r_plane[4]) -{ - /* TODO: put that into private data. */ - float viewinv[4][4]; - DRW_view_viewmat_get(NULL, viewinv, true); - float *camera_z_axis = viewinv[2]; - float *camera_pos = viewinv[3]; - - /* Find the normal most likely to represent the grease pencil object. */ - /* TODO: This does not work quite well if you use - * strokes not aligned with the object axes. Maybe we could try to - * compute the minimum axis of all strokes. But this would be more - * computationally heavy and should go into the GPData evaluation. */ - const BoundBox *bbox = BKE_object_boundbox_get(ob); - /* Convert bbox to matrix */ - float mat[4][4], size[3], center[3]; - BKE_boundbox_calc_size_aabb(bbox, size); - BKE_boundbox_calc_center_aabb(bbox, center); - unit_m4(mat); - copy_v3_v3(mat[3], center); - /* Avoid division by 0.0 later. */ - add_v3_fl(size, 1e-8f); - rescale_m4(mat, size); - /* BBox space to World. */ - mul_m4_m4m4(mat, ob->obmat, mat); - /* BBox center in world space. */ - copy_v3_v3(center, mat[3]); - /* View Vector. */ - if (DRW_view_is_persp_get(NULL)) { - /* BBox center to camera vector. */ - sub_v3_v3v3(r_plane, camera_pos, mat[3]); - } - else { - copy_v3_v3(r_plane, camera_z_axis); - } - /* World to BBox space. */ - invert_m4(mat); - /* Normalize the vector in BBox space. */ - mul_mat3_m4_v3(mat, r_plane); - normalize_v3(r_plane); - - transpose_m4(mat); - /* mat is now a "normal" matrix which will transform - * BBox space normal to world space. */ - mul_mat3_m4_v3(mat, r_plane); - normalize_v3(r_plane); - - plane_from_point_normal_v3(r_plane, center, r_plane); -} - -void OVERLAY_outline_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()) { - /* TODO: only alloc if needed. */ - 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)}); - - if (pd->antialiasing.enabled) { - GPU_framebuffer_ensure_config(&fbl->outlines_resolve_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx), - GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx), - }); - } - else { - GPU_framebuffer_ensure_config(&fbl->outlines_resolve_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), - }); - } - } -} - -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_expand = (U.pixelsize > 1.0) || (outline_width > 2.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_geom = OVERLAY_shader_outline_prepass(pd->xray_enabled_and_not_wire); - - pd->outlines_grp = grp = DRW_shgroup_create(sh_geom, psl->outlines_prepass_ps); - DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); - - GPUShader *sh_geom_ptcloud = OVERLAY_shader_outline_prepass_pointcloud(); - - pd->outlines_ptcloud_grp = grp = DRW_shgroup_create(sh_geom_ptcloud, psl->outlines_prepass_ps); - DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); - - GPUShader *sh_gpencil = OVERLAY_shader_outline_prepass_gpencil(); - - pd->outlines_gpencil_grp = grp = DRW_shgroup_create(sh_gpencil, psl->outlines_prepass_ps); - DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); - DRW_shgroup_uniform_float_copy(grp, "gpStrokeIndexOffset", 0.0); - - GPUShader *sh_curves = OVERLAY_shader_outline_prepass_curves(); - pd->outlines_curves_grp = grp = DRW_shgroup_create(sh_curves, psl->outlines_prepass_ps); - DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); - } - - /* outlines_prepass_ps is still needed for selection of probes. */ - if (!(pd->v3d_flag & V3D_SELECT_OUTLINE)) { - return; - } - - { - /* We can only do alpha blending with lineOutput just after clearing the buffer. */ - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL; - DRW_PASS_CREATE(psl->outlines_detect_ps, state); - - GPUShader *sh = OVERLAY_shader_outline_detect(); - - 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_bool_copy(grp, "doThickOutlines", do_expand); - DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", pd->antialiasing.enabled); - DRW_shgroup_uniform_bool_copy(grp, "isXrayWires", pd->xray_enabled_and_not_wire); - DRW_shgroup_uniform_texture_ref(grp, "outlineId", &txl->outlines_id_tx); - DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth); - DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &txl->temp_depth_tx); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_call_procedural_triangles(grp, NULL, 1); - } -} - -typedef struct iterData { - Object *ob; - DRWShadingGroup *stroke_grp; - DRWShadingGroup *fill_grp; - int cfra; - float plane[4]; -} iterData; - -static void gpencil_layer_cache_populate(bGPDlayer *gpl, - bGPDframe *UNUSED(gpf), - bGPDstroke *UNUSED(gps), - void *thunk) -{ - iterData *iter = (iterData *)thunk; - bGPdata *gpd = (bGPdata *)iter->ob->data; - - const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0; - const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D); - - float object_scale = mat4_to_scale(iter->ob->obmat); - /* Negate thickness sign to tag that strokes are in screen space. - * Convert to world units (by default, 1 meter = 2000 pixels). */ - float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / 2000.0f); - - DRWShadingGroup *grp = iter->stroke_grp = DRW_shgroup_create_sub(iter->stroke_grp); - DRW_shgroup_uniform_bool_copy(grp, "gpStrokeOrder3d", is_stroke_order_3d); - DRW_shgroup_uniform_float_copy(grp, "gpThicknessScale", object_scale); - DRW_shgroup_uniform_float_copy(grp, "gpThicknessOffset", (float)gpl->line_change); - DRW_shgroup_uniform_float_copy(grp, "gpThicknessWorldScale", thickness_scale); - DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", iter->plane); -} - -static void gpencil_stroke_cache_populate(bGPDlayer *UNUSED(gpl), - bGPDframe *UNUSED(gpf), - bGPDstroke *gps, - void *thunk) -{ - iterData *iter = (iterData *)thunk; - - MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter->ob, gps->mat_nr + 1); - - bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; - bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0; - // TODO: What about simplify Fill? - bool show_fill = (gps->tot_triangles > 0) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0; - - if (hide_material) { - return; - } - - if (show_fill) { - struct GPUBatch *geom = DRW_cache_gpencil_fills_get(iter->ob, iter->cfra); - int vfirst = gps->runtime.fill_start * 3; - int vcount = gps->tot_triangles * 3; - DRW_shgroup_call_range(iter->fill_grp, iter->ob, geom, vfirst, vcount); - } - - if (show_stroke) { - struct GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter->ob, iter->cfra); - /* Start one vert before to have gl_InstanceID > 0 (see shader). */ - int vfirst = gps->runtime.stroke_start - 1; - /* Include "potential" cyclic vertex and start adj vertex (see shader). */ - int vcount = gps->totpoints + 1 + 1; - DRW_shgroup_call_instance_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount); - } -} - -static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob) -{ - /* No outlines in edit mode. */ - bGPdata *gpd = (bGPdata *)ob->data; - if (gpd && GPENCIL_ANY_MODE(gpd)) { - return; - } - - iterData iter = { - .ob = ob, - .stroke_grp = pd->outlines_gpencil_grp, - .fill_grp = DRW_shgroup_create_sub(pd->outlines_gpencil_grp), - .cfra = pd->cfra, - }; - - if (gpd->draw_mode == GP_DRAWMODE_2D) { - gpencil_depth_plane(ob, iter.plane); - } - - BKE_gpencil_visible_stroke_advanced_iter(NULL, - ob, - gpencil_layer_cache_populate, - gpencil_stroke_cache_populate, - &iter, - false, - pd->cfra); -} - -static void OVERLAY_outline_volume(OVERLAY_PrivateData *pd, Object *ob) -{ - struct GPUBatch *geom = DRW_cache_volume_selection_surface_get(ob); - if (geom == NULL) { - return; - } - - DRWShadingGroup *shgroup = pd->outlines_grp; - DRW_shgroup_call(shgroup, geom, ob); -} - -static void OVERLAY_outline_curves(OVERLAY_PrivateData *pd, Object *ob) -{ - DRWShadingGroup *shgroup = pd->outlines_curves_grp; - DRW_shgroup_curves_create_sub(ob, shgroup, NULL); -} - -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; - const bool draw_outline = ob->dt > OB_BOUNDBOX; - - /* Early exit: outlines of bounding boxes are not drawn. */ - if (!draw_outline) { - return; - } - - if (ob->type == OB_GPENCIL) { - OVERLAY_outline_gpencil(pd, ob); - return; - } - - if (ob->type == OB_VOLUME) { - OVERLAY_outline_volume(pd, ob); - return; - } - - if (ob->type == OB_CURVES) { - OVERLAY_outline_curves(pd, ob); - return; - } - - if (ob->type == OB_POINTCLOUD && pd->wireframe_mode) { - /* Looks bad in this case. Could be relaxed if we draw a - * wireframe of some sort in the future. */ - 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) { - shgroup = (ob->type == OB_POINTCLOUD) ? pd->outlines_ptcloud_grp : pd->outlines_grp; - } - } - - if (shgroup && geom) { - if (ob->type == OB_POINTCLOUD) { - /* Draw range to avoid drawcall batching messing up the instance attribute. */ - DRW_shgroup_call_instance_range(shgroup, ob, geom, 0, 0); - } - else { - 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; - const 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_stencil(fbl->outlines_prepass_fb, clearcol, 1.0f, 0x00); - DRW_draw_pass(psl->outlines_prepass_ps); - - /* Search outline pixels */ - GPU_framebuffer_bind(fbl->outlines_resolve_fb); - DRW_draw_pass(psl->outlines_detect_ps); - - DRW_stats_group_end(); - } -} diff --git a/source/blender/draw/engines/overlay/overlay_outline.cc b/source/blender/draw/engines/overlay/overlay_outline.cc new file mode 100644 index 00000000000..e308775dc6e --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_outline.cc @@ -0,0 +1,378 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "BKE_global.h" +#include "BKE_gpencil.h" + +#include "BKE_object.h" + +#include "DNA_gpencil_types.h" + +#include "UI_resources.h" + +#include "overlay_private.hh" + +/* Returns the normal plane in NDC space. */ +static void gpencil_depth_plane(Object *ob, float r_plane[4]) +{ + /* TODO: put that into private data. */ + float viewinv[4][4]; + DRW_view_viewmat_get(nullptr, viewinv, true); + float *camera_z_axis = viewinv[2]; + float *camera_pos = viewinv[3]; + + /* Find the normal most likely to represent the grease pencil object. */ + /* TODO: This does not work quite well if you use + * strokes not aligned with the object axes. Maybe we could try to + * compute the minimum axis of all strokes. But this would be more + * computationally heavy and should go into the GPData evaluation. */ + const BoundBox *bbox = BKE_object_boundbox_get(ob); + /* Convert bbox to matrix */ + float mat[4][4], size[3], center[3]; + BKE_boundbox_calc_size_aabb(bbox, size); + BKE_boundbox_calc_center_aabb(bbox, center); + unit_m4(mat); + copy_v3_v3(mat[3], center); + /* Avoid division by 0.0 later. */ + add_v3_fl(size, 1e-8f); + rescale_m4(mat, size); + /* BBox space to World. */ + mul_m4_m4m4(mat, ob->obmat, mat); + /* BBox center in world space. */ + copy_v3_v3(center, mat[3]); + /* View Vector. */ + if (DRW_view_is_persp_get(nullptr)) { + /* BBox center to camera vector. */ + sub_v3_v3v3(r_plane, camera_pos, mat[3]); + } + else { + copy_v3_v3(r_plane, camera_z_axis); + } + /* World to BBox space. */ + invert_m4(mat); + /* Normalize the vector in BBox space. */ + mul_mat3_m4_v3(mat, r_plane); + normalize_v3(r_plane); + + transpose_m4(mat); + /* mat is now a "normal" matrix which will transform + * BBox space normal to world space. */ + mul_mat3_m4_v3(mat, r_plane); + normalize_v3(r_plane); + + plane_from_point_normal_v3(r_plane, center, r_plane); +} + +void OVERLAY_outline_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()) { + /* TODO: only alloc if needed. */ + DRW_texture_ensure_fullscreen_2d(&txl->temp_depth_tx, GPU_DEPTH24_STENCIL8, DRWTextureFlag(0)); + DRW_texture_ensure_fullscreen_2d(&txl->outlines_id_tx, GPU_R16UI, DRWTextureFlag(0)); + + GPU_framebuffer_ensure_config( + &fbl->outlines_prepass_fb, + {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(txl->outlines_id_tx)}); + + if (pd->antialiasing.enabled) { + GPU_framebuffer_ensure_config(&fbl->outlines_resolve_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx), + GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx), + }); + } + else { + GPU_framebuffer_ensure_config(&fbl->outlines_resolve_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), + }); + } + } +} + +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 = nullptr; + + const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH); + const bool do_expand = (U.pixelsize > 1.0) || (outline_width > 2.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_geom = OVERLAY_shader_outline_prepass(pd->xray_enabled_and_not_wire); + + pd->outlines_grp = grp = DRW_shgroup_create(sh_geom, psl->outlines_prepass_ps); + DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); + + GPUShader *sh_geom_ptcloud = OVERLAY_shader_outline_prepass_pointcloud(); + + pd->outlines_ptcloud_grp = grp = DRW_shgroup_create(sh_geom_ptcloud, psl->outlines_prepass_ps); + DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); + + GPUShader *sh_gpencil = OVERLAY_shader_outline_prepass_gpencil(); + + pd->outlines_gpencil_grp = grp = DRW_shgroup_create(sh_gpencil, psl->outlines_prepass_ps); + DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); + DRW_shgroup_uniform_float_copy(grp, "gpStrokeIndexOffset", 0.0); + + GPUShader *sh_curves = OVERLAY_shader_outline_prepass_curves(); + pd->outlines_curves_grp = grp = DRW_shgroup_create(sh_curves, psl->outlines_prepass_ps); + DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); + } + + /* outlines_prepass_ps is still needed for selection of probes. */ + if (!(pd->v3d_flag & V3D_SELECT_OUTLINE)) { + return; + } + + { + /* We can only do alpha blending with lineOutput just after clearing the buffer. */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL; + DRW_PASS_CREATE(psl->outlines_detect_ps, state); + + GPUShader *sh = OVERLAY_shader_outline_detect(); + + 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_bool_copy(grp, "doThickOutlines", do_expand); + DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", pd->antialiasing.enabled); + DRW_shgroup_uniform_bool_copy(grp, "isXrayWires", pd->xray_enabled_and_not_wire); + DRW_shgroup_uniform_texture_ref(grp, "outlineId", &txl->outlines_id_tx); + DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &txl->temp_depth_tx); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_call_procedural_triangles(grp, nullptr, 1); + } +} + +typedef struct iterData { + Object *ob; + DRWShadingGroup *stroke_grp; + DRWShadingGroup *fill_grp; + int cfra; + float plane[4]; +} iterData; + +static void gpencil_layer_cache_populate(bGPDlayer *gpl, + bGPDframe *UNUSED(gpf), + bGPDstroke *UNUSED(gps), + void *thunk) +{ + iterData *iter = (iterData *)thunk; + bGPdata *gpd = (bGPdata *)iter->ob->data; + + const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0; + const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D); + + float object_scale = mat4_to_scale(iter->ob->obmat); + /* Negate thickness sign to tag that strokes are in screen space. + * Convert to world units (by default, 1 meter = 2000 pixels). */ + float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / 2000.0f); + + DRWShadingGroup *grp = iter->stroke_grp = DRW_shgroup_create_sub(iter->stroke_grp); + DRW_shgroup_uniform_bool_copy(grp, "gpStrokeOrder3d", is_stroke_order_3d); + DRW_shgroup_uniform_float_copy(grp, "gpThicknessScale", object_scale); + DRW_shgroup_uniform_float_copy(grp, "gpThicknessOffset", (float)gpl->line_change); + DRW_shgroup_uniform_float_copy(grp, "gpThicknessWorldScale", thickness_scale); + DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", iter->plane); +} + +static void gpencil_stroke_cache_populate(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) +{ + iterData *iter = (iterData *)thunk; + + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter->ob, gps->mat_nr + 1); + + bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; + bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0; + // TODO: What about simplify Fill? + bool show_fill = (gps->tot_triangles > 0) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0; + + if (hide_material) { + return; + } + + if (show_fill) { + struct GPUBatch *geom = DRW_cache_gpencil_fills_get(iter->ob, iter->cfra); + int vfirst = gps->runtime.fill_start * 3; + int vcount = gps->tot_triangles * 3; + DRW_shgroup_call_range(iter->fill_grp, iter->ob, geom, vfirst, vcount); + } + + if (show_stroke) { + struct GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter->ob, iter->cfra); + /* Start one vert before to have gl_InstanceID > 0 (see shader). */ + int vfirst = gps->runtime.stroke_start - 1; + /* Include "potential" cyclic vertex and start adj vertex (see shader). */ + int vcount = gps->totpoints + 1 + 1; + DRW_shgroup_call_instance_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount); + } +} + +static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob) +{ + /* No outlines in edit mode. */ + bGPdata *gpd = (bGPdata *)ob->data; + if (gpd && GPENCIL_ANY_MODE(gpd)) { + return; + } + + iterData iter{}; + iter.ob = ob; + iter.stroke_grp = pd->outlines_gpencil_grp; + iter.fill_grp = DRW_shgroup_create_sub(pd->outlines_gpencil_grp); + iter.cfra = pd->cfra; + + if (gpd->draw_mode == GP_DRAWMODE_2D) { + gpencil_depth_plane(ob, iter.plane); + } + + BKE_gpencil_visible_stroke_advanced_iter(nullptr, + ob, + gpencil_layer_cache_populate, + gpencil_stroke_cache_populate, + &iter, + false, + pd->cfra); +} + +static void OVERLAY_outline_volume(OVERLAY_PrivateData *pd, Object *ob) +{ + struct GPUBatch *geom = DRW_cache_volume_selection_surface_get(ob); + if (geom == nullptr) { + return; + } + + DRWShadingGroup *shgroup = pd->outlines_grp; + DRW_shgroup_call(shgroup, geom, ob); +} + +static void OVERLAY_outline_curves(OVERLAY_PrivateData *pd, Object *ob) +{ + DRWShadingGroup *shgroup = pd->outlines_curves_grp; + DRW_shgroup_curves_create_sub(ob, shgroup, nullptr); +} + +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 = nullptr; + const bool draw_outline = ob->dt > OB_BOUNDBOX; + + /* Early exit: outlines of bounding boxes are not drawn. */ + if (!draw_outline) { + return; + } + + if (ob->type == OB_GPENCIL) { + OVERLAY_outline_gpencil(pd, ob); + return; + } + + if (ob->type == OB_VOLUME) { + OVERLAY_outline_volume(pd, ob); + return; + } + + if (ob->type == OB_CURVES) { + OVERLAY_outline_curves(pd, ob); + return; + } + + if (ob->type == OB_POINTCLOUD && pd->wireframe_mode) { + /* Looks bad in this case. Could be relaxed if we draw a + * wireframe of some sort in the future. */ + 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, nullptr); + } + else { + geom = DRW_cache_object_surface_get(ob); + } + + if (geom) { + shgroup = (ob->type == OB_POINTCLOUD) ? pd->outlines_ptcloud_grp : pd->outlines_grp; + } + } + + if (shgroup && geom) { + if (ob->type == OB_POINTCLOUD) { + /* Draw range to avoid drawcall batching messing up the instance attribute. */ + DRW_shgroup_call_instance_range(shgroup, ob, geom, 0, 0); + } + else { + 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; + const float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + bool do_outlines = psl->outlines_prepass_ps != nullptr && + !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_stencil(fbl->outlines_prepass_fb, clearcol, 1.0f, 0x00); + DRW_draw_pass(psl->outlines_prepass_ps); + + /* Search outline pixels */ + GPU_framebuffer_bind(fbl->outlines_resolve_fb); + DRW_draw_pass(psl->outlines_detect_ps); + + DRW_stats_group_end(); + } +} diff --git a/source/blender/draw/engines/overlay/overlay_paint.c b/source/blender/draw/engines/overlay/overlay_paint.c deleted file mode 100644 index c730c702a8d..00000000000 --- a/source/blender/draw/engines/overlay/overlay_paint.c +++ /dev/null @@ -1,274 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "DRW_render.h" - -#include "BKE_image.h" - -#include "DNA_mesh_types.h" - -#include "DEG_depsgraph_query.h" - -#include "overlay_private.h" - -/* Check if the given object is rendered (partially) transparent */ -static bool paint_object_is_rendered_transparent(View3D *v3d, Object *ob) -{ - if (v3d->shading.type == OB_WIRE) { - return true; - } - if (v3d->shading.type == OB_SOLID) { - if (v3d->shading.flag & V3D_SHADING_XRAY) { - return true; - } - - if (ob && v3d->shading.color_type == V3D_SHADING_OBJECT_COLOR) { - return ob->color[3] < 1.0f; - } - if (ob && ob->type == OB_MESH && ob->data && - v3d->shading.color_type == V3D_SHADING_MATERIAL_COLOR) { - Mesh *me = ob->data; - for (int i = 0; i < me->totcol; i++) { - Material *mat = BKE_object_material_get_eval(ob, i + 1); - if (mat && mat->a < 1.0f) { - return true; - } - } - } - } - - /* Check object display types. */ - if (ob && ELEM(ob->dt, OB_WIRE, OB_BOUNDBOX)) { - return true; - } - - return false; -} - -void OVERLAY_paint_init(OVERLAY_Data *vedata) -{ - OVERLAY_StorageList *stl = vedata->stl; - OVERLAY_PrivateData *pd = stl->pd; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - pd->painting.in_front = pd->use_in_front && draw_ctx->obact && - (draw_ctx->obact->dtx & OB_DRAW_IN_FRONT); - pd->painting.alpha_blending = paint_object_is_rendered_transparent(draw_ctx->v3d, - draw_ctx->obact); -} - -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 is_edit_mode = (pd->ctx_mode == CTX_MODE_EDIT_MESH); - const bool draw_contours = !is_edit_mode && - (pd->overlay.wpaint_flag & V3D_OVERLAY_WPAINT_CONTOURS) != 0; - float opacity = 0.0f; - pd->paint_depth_grp = NULL; - psl->paint_depth_ps = NULL; - - switch (pd->ctx_mode) { - case CTX_MODE_POSE: - case CTX_MODE_EDIT_MESH: - case CTX_MODE_PAINT_WEIGHT: { - opacity = is_edit_mode ? 1.0 : pd->overlay.weight_paint_mode_opacity; - 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); - - const bool do_shading = draw_ctx->v3d->shading.type != OB_WIRE; - - sh = OVERLAY_shader_paint_weight(do_shading); - 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_float_copy(grp, "opacity", opacity); - DRW_shgroup_uniform_texture(grp, "colorramp", G_draw.weight_ramp); - - /* Arbitrary light to give a hint of the geometry behind the weights. */ - if (do_shading) { - float light_dir[3]; - copy_v3_fl3(light_dir, 0.0f, 0.5f, 0.86602f); - normalize_v3(light_dir); - DRW_shgroup_uniform_vec3_copy(grp, "light_dir", light_dir); - } - - if (pd->painting.alpha_blending) { - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - DRW_PASS_CREATE(psl->paint_depth_ps, state | pd->clipping_state); - sh = OVERLAY_shader_depth_only(); - pd->paint_depth_grp = DRW_shgroup_create(sh, psl->paint_depth_ps); - } - } - 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 |= pd->painting.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", pd->painting.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 = BKE_image_get_gpu_texture(imapaint->stencil, NULL, NULL); - - 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_orig = DEG_get_original_object(ob)->data; - const bool is_edit_mode = (pd->ctx_mode == CTX_MODE_EDIT_MESH); - const bool use_wire = !is_edit_mode && (pd->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE); - const bool use_face_sel = !is_edit_mode && (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL); - const bool use_vert_sel = !is_edit_mode && (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL); - - if (ELEM(ob->mode, OB_MODE_WEIGHT_PAINT, OB_MODE_EDIT)) { - if (pd->paint_surf_grp) { - geom = DRW_cache_mesh_surface_weights_get(ob); - DRW_shgroup_call(pd->paint_surf_grp, geom, ob); - } - if (pd->paint_depth_grp) { - geom = DRW_cache_mesh_surface_weights_get(ob); - DRW_shgroup_call(pd->paint_depth_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_StorageList *stl = vedata->stl; - OVERLAY_PrivateData *pd = stl->pd; - - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_FramebufferList *fbl = vedata->fbl; - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(pd->painting.in_front ? fbl->overlay_in_front_fb : - fbl->overlay_default_fb); - } - - if (psl->paint_depth_ps) { - DRW_draw_pass(psl->paint_depth_ps); - } - if (psl->paint_color_ps) { - DRW_draw_pass(psl->paint_color_ps); - } - if (psl->paint_overlay_ps) { - DRW_draw_pass(psl->paint_overlay_ps); - } -} diff --git a/source/blender/draw/engines/overlay/overlay_paint.cc b/source/blender/draw/engines/overlay/overlay_paint.cc new file mode 100644 index 00000000000..d2573d1db0b --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_paint.cc @@ -0,0 +1,275 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "BKE_image.h" + +#include "DNA_mesh_types.h" + +#include "DEG_depsgraph_query.h" + +#include "overlay_private.hh" + +/* Check if the given object is rendered (partially) transparent */ +static bool paint_object_is_rendered_transparent(View3D *v3d, Object *ob) +{ + if (v3d->shading.type == OB_WIRE) { + return true; + } + if (v3d->shading.type == OB_SOLID) { + if (v3d->shading.flag & V3D_SHADING_XRAY) { + return true; + } + + if (ob && v3d->shading.color_type == V3D_SHADING_OBJECT_COLOR) { + return ob->color[3] < 1.0f; + } + if (ob && ob->type == OB_MESH && ob->data && + v3d->shading.color_type == V3D_SHADING_MATERIAL_COLOR) { + Mesh *me = static_cast(ob->data); + for (int i = 0; i < me->totcol; i++) { + Material *mat = BKE_object_material_get_eval(ob, i + 1); + if (mat && mat->a < 1.0f) { + return true; + } + } + } + } + + /* Check object display types. */ + if (ob && ELEM(ob->dt, OB_WIRE, OB_BOUNDBOX)) { + return true; + } + + return false; +} + +void OVERLAY_paint_init(OVERLAY_Data *vedata) +{ + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PrivateData *pd = stl->pd; + const DRWContextState *draw_ctx = DRW_context_state_get(); + + pd->painting.in_front = pd->use_in_front && draw_ctx->obact && + (draw_ctx->obact->dtx & OB_DRAW_IN_FRONT); + pd->painting.alpha_blending = paint_object_is_rendered_transparent(draw_ctx->v3d, + draw_ctx->obact); +} + +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 is_edit_mode = (pd->ctx_mode == CTX_MODE_EDIT_MESH); + const bool draw_contours = !is_edit_mode && + (pd->overlay.wpaint_flag & V3D_OVERLAY_WPAINT_CONTOURS) != 0; + float opacity = 0.0f; + pd->paint_depth_grp = nullptr; + psl->paint_depth_ps = nullptr; + + switch (pd->ctx_mode) { + case CTX_MODE_POSE: + case CTX_MODE_EDIT_MESH: + case CTX_MODE_PAINT_WEIGHT: { + opacity = is_edit_mode ? 1.0 : pd->overlay.weight_paint_mode_opacity; + 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); + + const bool do_shading = draw_ctx->v3d->shading.type != OB_WIRE; + + sh = OVERLAY_shader_paint_weight(do_shading); + 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_float_copy(grp, "opacity", opacity); + DRW_shgroup_uniform_texture(grp, "colorramp", G_draw.weight_ramp); + + /* Arbitrary light to give a hint of the geometry behind the weights. */ + if (do_shading) { + float light_dir[3]; + copy_v3_fl3(light_dir, 0.0f, 0.5f, 0.86602f); + normalize_v3(light_dir); + DRW_shgroup_uniform_vec3_copy(grp, "light_dir", light_dir); + } + + if (pd->painting.alpha_blending) { + state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + DRW_PASS_CREATE(psl->paint_depth_ps, state | pd->clipping_state); + sh = OVERLAY_shader_depth_only(); + pd->paint_depth_grp = DRW_shgroup_create(sh, psl->paint_depth_ps); + } + } + 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 |= pd->painting.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", pd->painting.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 != nullptr; + + 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 = BKE_image_get_gpu_texture(imapaint->stencil, nullptr, nullptr); + + 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 = nullptr; + pd->paint_surf_grp = nullptr; + } + + { + 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); + const float4 color = {1.0f, 1.0f, 1.0f, 0.2f}; + DRW_shgroup_uniform_vec4_copy(grp, "color", color); + 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 = nullptr; + + const Mesh *me_orig = static_cast(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 = nullptr; + + const Mesh *me_orig = static_cast(DEG_get_original_object(ob)->data); + const bool is_edit_mode = (pd->ctx_mode == CTX_MODE_EDIT_MESH); + const bool use_wire = !is_edit_mode && (pd->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE); + const bool use_face_sel = !is_edit_mode && (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL); + const bool use_vert_sel = !is_edit_mode && (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL); + + if (ELEM(ob->mode, OB_MODE_WEIGHT_PAINT, OB_MODE_EDIT)) { + if (pd->paint_surf_grp) { + geom = DRW_cache_mesh_surface_weights_get(ob); + DRW_shgroup_call(pd->paint_surf_grp, geom, ob); + } + if (pd->paint_depth_grp) { + geom = DRW_cache_mesh_surface_weights_get(ob); + DRW_shgroup_call(pd->paint_depth_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_StorageList *stl = vedata->stl; + OVERLAY_PrivateData *pd = stl->pd; + + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_FramebufferList *fbl = vedata->fbl; + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(pd->painting.in_front ? fbl->overlay_in_front_fb : + fbl->overlay_default_fb); + } + + if (psl->paint_depth_ps) { + DRW_draw_pass(psl->paint_depth_ps); + } + if (psl->paint_color_ps) { + DRW_draw_pass(psl->paint_color_ps); + } + if (psl->paint_overlay_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 deleted file mode 100644 index b985bfb24bf..00000000000 --- a/source/blender/draw/engines/overlay/overlay_particle.c +++ /dev/null @@ -1,207 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * 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; - OVERLAY_FramebufferList *fbl = vedata->fbl; - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(fbl->overlay_default_fb); - } - - 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(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_texture(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(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_texture(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. */ - - /* NOTE(fclem): Is color even useful in our modern context? */ - Material *ma = BKE_object_material_get_eval(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_attrs(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_particle.cc b/source/blender/draw/engines/overlay/overlay_particle.cc new file mode 100644 index 00000000000..6f77a777ba0 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_particle.cc @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * 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.hh" + +/* -------------------------------------------------------------------- */ +/** \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 == nullptr) { + /* 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 = static_cast(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 == nullptr) { + 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, nullptr); + } + + 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, nullptr); + } + + 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, nullptr); + } +} + +void OVERLAY_edit_particle_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_FramebufferList *fbl = vedata->fbl; + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_default_fb); + } + + 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(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_texture(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(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_texture(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 = nullptr; + DRWShadingGroup *grp; + + /* TODO(fclem): Here would be a good place for preemptive culling. */ + + /* NOTE(fclem): Is color even useful in our modern context? */ + Material *ma = BKE_object_material_get_eval(ob, part->omat); + float color[4] = {0.6f, 0.6f, 0.6f, part->draw_size}; + if (ma != nullptr) { + 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, nullptr); + 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_attrs(grp, nullptr, 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 deleted file mode 100644 index 0a783c44029..00000000000 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ /dev/null @@ -1,776 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup DNA - */ - -#pragma once - -#include "DRW_render.h" - -#include "overlay_shader_shared.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __APPLE__ -# define USE_GEOM_SHADER_WORKAROUND 1 -#else -# define USE_GEOM_SHADER_WORKAROUND 0 -#endif - -/* Needed for eSpaceImage_UVDT_Stretch and eMaskOverlayMode */ -#include "DNA_mask_types.h" -#include "DNA_space_types.h" -/* Forward declarations */ -struct ImBuf; - -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 *overlay_line_in_front_fb; - struct GPUFrameBuffer *outlines_prepass_fb; - struct GPUFrameBuffer *outlines_resolve_fb; -} OVERLAY_FramebufferList; - -typedef struct OVERLAY_TextureList { - struct GPUTexture *temp_depth_tx; - struct GPUTexture *dummy_depth_tx; - struct GPUTexture *outlines_id_tx; - struct GPUTexture *overlay_color_tx; - struct GPUTexture *overlay_line_tx; -} OVERLAY_TextureList; - -#define NOT_IN_FRONT 0 -#define IN_FRONT 1 - -typedef enum OVERLAY_UVLineStyle { - OVERLAY_UV_LINE_STYLE_OUTLINE = 0, - OVERLAY_UV_LINE_STYLE_DASH = 1, - OVERLAY_UV_LINE_STYLE_BLACK = 2, - OVERLAY_UV_LINE_STYLE_WHITE = 3, - OVERLAY_UV_LINE_STYLE_SHADOW = 4, -} OVERLAY_UVLineStyle; - -typedef struct OVERLAY_PassList { - DRWPass *antialiasing_ps; - DRWPass *armature_ps[2]; - DRWPass *armature_bone_select_ps; - DRWPass *armature_transp_ps[2]; - DRWPass *background_ps; - DRWPass *clipping_frustum_ps; - DRWPass *edit_curve_wire_ps[2]; - DRWPass *edit_curve_handle_ps; - DRWPass *edit_gpencil_ps; - DRWPass *edit_gpencil_gizmos_ps; - DRWPass *edit_gpencil_curve_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_curves_points_ps[2]; - DRWPass *edit_mesh_analysis_ps; - DRWPass *edit_mesh_normals_ps; - DRWPass *edit_particle_ps; - DRWPass *edit_text_cursor_ps; - DRWPass *edit_text_selection_ps; - DRWPass *edit_text_highlight_ps; - DRWPass *edit_text_wire_ps[2]; - DRWPass *edit_uv_edges_ps; - DRWPass *edit_uv_verts_ps; - DRWPass *edit_uv_faces_ps; - DRWPass *edit_uv_stretching_ps; - DRWPass *edit_uv_tiled_image_borders_ps; - DRWPass *edit_uv_stencil_ps; - DRWPass *edit_uv_mask_ps; - DRWPass *extra_ps[2]; - DRWPass *extra_blend_ps; - DRWPass *extra_centers_ps; - DRWPass *extra_grid_ps; - DRWPass *gpencil_canvas_ps; - DRWPass *facing_ps[2]; - DRWPass *fade_ps[2]; - DRWPass *mode_transfer_ps[2]; - DRWPass *grid_ps; - DRWPass *image_background_ps; - DRWPass *image_background_scene_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 *image_foreground_scene_ps; - DRWPass *metaball_ps[2]; - DRWPass *motion_paths_ps; - DRWPass *outlines_prepass_ps; - DRWPass *outlines_detect_ps; - DRWPass *outlines_resolve_ps; - DRWPass *paint_color_ps; - DRWPass *paint_depth_ps; - DRWPass *paint_overlay_ps; - DRWPass *particle_ps; - DRWPass *pointcloud_ps; - DRWPass *sculpt_mask_ps; - DRWPass *sculpt_curves_selection_ps; - DRWPass *volume_ps; - DRWPass *wireframe_ps; - DRWPass *wireframe_xray_ps; - DRWPass *xray_fade_ps; -} OVERLAY_PassList; - -/* Data used by GLSL shader. */ -typedef struct OVERLAY_ShadingData { - /** Wireframe */ - float wire_step_param; - float wire_opacity; - /** 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 *extra_points; - - 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 *solid_quad; - - DRWCallBuffer *speaker; - - DRWShadingGroup *extra_wire; - DRWShadingGroup *extra_loose_points; -} OVERLAY_ExtraCallBuffers; - -typedef struct OVERLAY_ArmatureCallBuffersInner { - DRWCallBuffer *box_outline; - DRWCallBuffer *box_fill; - - DRWCallBuffer *dof_lines; - DRWCallBuffer *dof_sphere; - - DRWCallBuffer *envelope_distance; - DRWCallBuffer *envelope_outline; - DRWCallBuffer *envelope_fill; - - DRWCallBuffer *octa_outline; - DRWCallBuffer *octa_fill; - - DRWCallBuffer *point_outline; - DRWCallBuffer *point_fill; - - DRWCallBuffer *stick; - - DRWCallBuffer *wire; - - DRWShadingGroup *custom_outline; - DRWShadingGroup *custom_fill; - DRWShadingGroup *custom_wire; - - GHash *custom_shapes_ghash; -} OVERLAY_ArmatureCallBuffersInner; - -typedef struct OVERLAY_ArmatureCallBuffers { - OVERLAY_ArmatureCallBuffersInner solid; - OVERLAY_ArmatureCallBuffersInner transp; -} 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_gpencil_points_grp; - DRWShadingGroup *edit_gpencil_wires_grp; - DRWShadingGroup *edit_gpencil_curve_handle_grp; - DRWShadingGroup *edit_gpencil_curve_points_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_particle_strand_grp; - DRWShadingGroup *edit_particle_point_grp; - DRWShadingGroup *edit_text_cursor_grp; - DRWShadingGroup *edit_text_selection_grp; - DRWShadingGroup *edit_text_wire_grp[2]; - DRWShadingGroup *edit_uv_verts_grp; - DRWShadingGroup *edit_uv_edges_grp; - DRWShadingGroup *edit_uv_shadow_edges_grp; - DRWShadingGroup *edit_uv_faces_grp; - DRWShadingGroup *edit_uv_face_dots_grp; - DRWShadingGroup *edit_uv_stretching_grp; - DRWShadingGroup *edit_curves_points_grp[2]; - DRWShadingGroup *extra_grid_grp; - DRWShadingGroup *facing_grp[2]; - DRWShadingGroup *fade_grp[2]; - DRWShadingGroup *flash_grp[2]; - DRWShadingGroup *motion_path_lines_grp; - DRWShadingGroup *motion_path_points_grp; - DRWShadingGroup *outlines_grp; - DRWShadingGroup *outlines_curves_grp; - DRWShadingGroup *outlines_ptcloud_grp; - DRWShadingGroup *outlines_gpencil_grp; - DRWShadingGroup *paint_depth_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 *pointcloud_dots_grp; - DRWShadingGroup *sculpt_mask_grp; - DRWShadingGroup *sculpt_curves_selection_grp; - DRWShadingGroup *volume_selection_surface_grp; - DRWShadingGroup *wires_grp[2][2]; /* With and without coloring. */ - DRWShadingGroup *wires_all_grp[2][2]; /* With and without coloring. */ - DRWShadingGroup *wires_hair_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_edit_text; - DRWView *view_reference_images; - DRWView *view_edit_curves_points; - - /** TODO: get rid of this. */ - 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; - char space_type; - bool clear_in_front; - bool use_in_front; - bool wireframe_mode; - bool hide_overlays; - bool xray_enabled; - bool xray_enabled_and_not_wire; - float xray_opacity; - short v3d_flag; /* TODO: move to #View3DOverlay. */ - short v3d_gridflag; /* TODO: move to #View3DOverlay. */ - int cfra; - DRWState clipping_state; - OVERLAY_ShadingData shdata; - OVERLAY_GridData grid_data; - - struct { - float grid_axes[3]; - float zplane_axes[3]; - OVERLAY_GridBits zneg_flag, zpos_flag, grid_flag; - } grid; - struct { - bool enabled; - bool do_depth_copy; - bool do_depth_infront_copy; - } antialiasing; - struct { - bool show_handles; - int handle_display; - } edit_curve; - struct { - float cursor_color[4]; - float selection_color[4]; - } edit_text; - struct { - 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 do_zbufclip; - } edit_curves; - struct { - bool use_weight; - int select_mode; - } edit_particle; - struct { - bool do_uv_overlay; - bool do_uv_shadow_overlay; - bool do_uv_stretching_overlay; - bool do_tiled_image_overlay; - bool do_tiled_image_border_overlay; - bool do_stencil_overlay; - bool do_mask_overlay; - - bool do_verts; - bool do_faces; - bool do_face_dots; - - float uv_opacity; - - int image_size[2]; - float image_aspect[2]; - - /* edge drawing */ - OVERLAY_UVLineStyle line_style; - float dash_length; - int do_smooth_wire; - - /* stretching overlay */ - float uv_aspect[2]; - eSpaceImage_UVDT_Stretch draw_type; - ListBase totals; - float total_area_ratio; - - /* stencil overlay */ - struct Image *stencil_image; - struct ImBuf *stencil_ibuf; - void *stencil_lock; - - /* mask overlay */ - Mask *mask; - eMaskOverlayMode mask_overlay_mode; - GPUTexture *mask_texture; - } edit_uv; - struct { - bool transparent; - bool show_relations; - bool do_pose_xray; - bool do_pose_fade_geom; - } armature; - struct { - bool in_front; - bool alpha_blending; - } painting; - struct { - DRWCallBuffer *handle[2]; - } mball; - struct { - double time; - bool any_animated; - } mode_transfer; -} OVERLAY_PrivateData; /* Transient data */ - -typedef struct OVERLAY_StorageList { - struct OVERLAY_PrivateData *pd; -} OVERLAY_StorageList; - -typedef struct OVERLAY_Instance { - GPUUniformBuf *grid_ubo; -} OVERLAY_Instance; - -typedef struct OVERLAY_Data { - void *engine_type; - OVERLAY_FramebufferList *fbl; - OVERLAY_TextureList *txl; - OVERLAY_PassList *psl; - OVERLAY_StorageList *stl; - - OVERLAY_Instance *instance; -} 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; - struct GPUVertFormat *point_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_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); -void OVERLAY_xray_fade_draw(OVERLAY_Data *vedata); -void OVERLAY_xray_depth_copy(OVERLAY_Data *vedata); -void OVERLAY_xray_depth_infront_copy(OVERLAY_Data *vedata); - -/** - * Return true if armature should be handled by the pose mode engine. - */ -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_background_cache_init(OVERLAY_Data *vedata); -void OVERLAY_background_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_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_gpencil_cache_init(OVERLAY_Data *vedata); -void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata); -void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob); -void OVERLAY_gpencil_draw(OVERLAY_Data *vedata); -void OVERLAY_edit_gpencil_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_volume_cache_init(OVERLAY_Data *vedata); -void OVERLAY_volume_cache_populate(OVERLAY_Data *vedata, Object *ob); -void OVERLAY_volume_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_edit_uv_init(OVERLAY_Data *vedata); -void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata); -void OVERLAY_edit_uv_cache_finish(OVERLAY_Data *vedata); -void OVERLAY_edit_uv_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_blend_draw(OVERLAY_Data *vedata); -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_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_point(OVERLAY_ExtraCallBuffers *cb, const float point[3], const float color[4]); -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], - int color_id); -void OVERLAY_empty_shape(OVERLAY_ExtraCallBuffers *cb, - const float mat[4][4], - float draw_size, - 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_facing_infront_draw(OVERLAY_Data *vedata); - -void OVERLAY_fade_init(OVERLAY_Data *vedata); -void OVERLAY_fade_cache_init(OVERLAY_Data *vedata); -void OVERLAY_fade_cache_populate(OVERLAY_Data *vedata, Object *ob); -void OVERLAY_fade_draw(OVERLAY_Data *vedata); -void OVERLAY_fade_infront_draw(OVERLAY_Data *vedata); - -void OVERLAY_mode_transfer_cache_init(OVERLAY_Data *vedata); -void OVERLAY_mode_transfer_cache_populate(OVERLAY_Data *vedata, Object *ob); -void OVERLAY_mode_transfer_draw(OVERLAY_Data *vedata); -void OVERLAY_mode_transfer_infront_draw(OVERLAY_Data *vedata); -void OVERLAY_mode_transfer_cache_finish(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_background_draw(OVERLAY_Data *vedata); -/** - * This function draws images that needs the view transform applied. - * It draws these images directly into the scene color buffer. - */ -void OVERLAY_image_scene_background_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_init(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_sculpt_curves_cache_init(OVERLAY_Data *vedata); -void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *ob); -void OVERLAY_sculpt_curves_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); - -void OVERLAY_edit_curves_init(OVERLAY_Data *vedata); -void OVERLAY_edit_curves_cache_init(OVERLAY_Data *vedata); -void OVERLAY_edit_curves_cache_populate(OVERLAY_Data *vedata, Object *ob); -void OVERLAY_edit_curves_draw(OVERLAY_Data *vedata); - -GPUShader *OVERLAY_shader_antialiasing(void); -GPUShader *OVERLAY_shader_armature_degrees_of_freedom_wire(void); -GPUShader *OVERLAY_shader_armature_degrees_of_freedom_solid(void); -GPUShader *OVERLAY_shader_armature_envelope(bool use_outline); -GPUShader *OVERLAY_shader_armature_shape(bool use_outline); -GPUShader *OVERLAY_shader_armature_shape_wire(void); -GPUShader *OVERLAY_shader_armature_sphere(bool use_outline); -GPUShader *OVERLAY_shader_armature_stick(void); -GPUShader *OVERLAY_shader_armature_wire(void); -GPUShader *OVERLAY_shader_background(void); -GPUShader *OVERLAY_shader_clipbound(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_gpencil_guide_point(void); -GPUShader *OVERLAY_shader_edit_gpencil_point(void); -GPUShader *OVERLAY_shader_edit_gpencil_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_edit_uv_edges_get(void); -GPUShader *OVERLAY_shader_edit_uv_edges_for_edge_select_get(void); -GPUShader *OVERLAY_shader_edit_uv_face_get(void); -GPUShader *OVERLAY_shader_edit_uv_face_dots_get(void); -GPUShader *OVERLAY_shader_edit_uv_verts_get(void); -GPUShader *OVERLAY_shader_edit_uv_stretching_area_get(void); -GPUShader *OVERLAY_shader_edit_uv_stretching_angle_get(void); -GPUShader *OVERLAY_shader_edit_uv_tiled_image_borders_get(void); -GPUShader *OVERLAY_shader_edit_uv_stencil_image(void); -GPUShader *OVERLAY_shader_edit_uv_mask_image(void); -GPUShader *OVERLAY_shader_extra(bool is_select); -GPUShader *OVERLAY_shader_extra_groundline(void); -GPUShader *OVERLAY_shader_extra_wire(bool use_object, bool is_select); -GPUShader *OVERLAY_shader_extra_loose_point(void); -GPUShader *OVERLAY_shader_extra_point(void); -GPUShader *OVERLAY_shader_facing(void); -GPUShader *OVERLAY_shader_gpencil_canvas(void); -GPUShader *OVERLAY_shader_grid(void); -GPUShader *OVERLAY_shader_grid_background(void); -GPUShader *OVERLAY_shader_grid_image(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_curves(void); -GPUShader *OVERLAY_shader_outline_prepass_gpencil(void); -GPUShader *OVERLAY_shader_outline_prepass_pointcloud(void); -GPUShader *OVERLAY_shader_extra_grid(void); -GPUShader *OVERLAY_shader_outline_detect(void); -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(bool shading); -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_sculpt_curves_selection(void); -GPUShader *OVERLAY_shader_volume_velocity(bool use_needle, bool use_mac); -GPUShader *OVERLAY_shader_volume_gridlines(bool color_with_flags, bool color_range); -GPUShader *OVERLAY_shader_wireframe(bool custom_bias); -GPUShader *OVERLAY_shader_wireframe_select(void); -GPUShader *OVERLAY_shader_xray_fade(void); - -OVERLAY_InstanceFormats *OVERLAY_shader_instance_formats_get(void); - -void OVERLAY_shader_free(void); - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh new file mode 100644 index 00000000000..0a783c44029 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_private.hh @@ -0,0 +1,776 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup DNA + */ + +#pragma once + +#include "DRW_render.h" + +#include "overlay_shader_shared.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __APPLE__ +# define USE_GEOM_SHADER_WORKAROUND 1 +#else +# define USE_GEOM_SHADER_WORKAROUND 0 +#endif + +/* Needed for eSpaceImage_UVDT_Stretch and eMaskOverlayMode */ +#include "DNA_mask_types.h" +#include "DNA_space_types.h" +/* Forward declarations */ +struct ImBuf; + +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 *overlay_line_in_front_fb; + struct GPUFrameBuffer *outlines_prepass_fb; + struct GPUFrameBuffer *outlines_resolve_fb; +} OVERLAY_FramebufferList; + +typedef struct OVERLAY_TextureList { + struct GPUTexture *temp_depth_tx; + struct GPUTexture *dummy_depth_tx; + struct GPUTexture *outlines_id_tx; + struct GPUTexture *overlay_color_tx; + struct GPUTexture *overlay_line_tx; +} OVERLAY_TextureList; + +#define NOT_IN_FRONT 0 +#define IN_FRONT 1 + +typedef enum OVERLAY_UVLineStyle { + OVERLAY_UV_LINE_STYLE_OUTLINE = 0, + OVERLAY_UV_LINE_STYLE_DASH = 1, + OVERLAY_UV_LINE_STYLE_BLACK = 2, + OVERLAY_UV_LINE_STYLE_WHITE = 3, + OVERLAY_UV_LINE_STYLE_SHADOW = 4, +} OVERLAY_UVLineStyle; + +typedef struct OVERLAY_PassList { + DRWPass *antialiasing_ps; + DRWPass *armature_ps[2]; + DRWPass *armature_bone_select_ps; + DRWPass *armature_transp_ps[2]; + DRWPass *background_ps; + DRWPass *clipping_frustum_ps; + DRWPass *edit_curve_wire_ps[2]; + DRWPass *edit_curve_handle_ps; + DRWPass *edit_gpencil_ps; + DRWPass *edit_gpencil_gizmos_ps; + DRWPass *edit_gpencil_curve_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_curves_points_ps[2]; + DRWPass *edit_mesh_analysis_ps; + DRWPass *edit_mesh_normals_ps; + DRWPass *edit_particle_ps; + DRWPass *edit_text_cursor_ps; + DRWPass *edit_text_selection_ps; + DRWPass *edit_text_highlight_ps; + DRWPass *edit_text_wire_ps[2]; + DRWPass *edit_uv_edges_ps; + DRWPass *edit_uv_verts_ps; + DRWPass *edit_uv_faces_ps; + DRWPass *edit_uv_stretching_ps; + DRWPass *edit_uv_tiled_image_borders_ps; + DRWPass *edit_uv_stencil_ps; + DRWPass *edit_uv_mask_ps; + DRWPass *extra_ps[2]; + DRWPass *extra_blend_ps; + DRWPass *extra_centers_ps; + DRWPass *extra_grid_ps; + DRWPass *gpencil_canvas_ps; + DRWPass *facing_ps[2]; + DRWPass *fade_ps[2]; + DRWPass *mode_transfer_ps[2]; + DRWPass *grid_ps; + DRWPass *image_background_ps; + DRWPass *image_background_scene_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 *image_foreground_scene_ps; + DRWPass *metaball_ps[2]; + DRWPass *motion_paths_ps; + DRWPass *outlines_prepass_ps; + DRWPass *outlines_detect_ps; + DRWPass *outlines_resolve_ps; + DRWPass *paint_color_ps; + DRWPass *paint_depth_ps; + DRWPass *paint_overlay_ps; + DRWPass *particle_ps; + DRWPass *pointcloud_ps; + DRWPass *sculpt_mask_ps; + DRWPass *sculpt_curves_selection_ps; + DRWPass *volume_ps; + DRWPass *wireframe_ps; + DRWPass *wireframe_xray_ps; + DRWPass *xray_fade_ps; +} OVERLAY_PassList; + +/* Data used by GLSL shader. */ +typedef struct OVERLAY_ShadingData { + /** Wireframe */ + float wire_step_param; + float wire_opacity; + /** 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 *extra_points; + + 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 *solid_quad; + + DRWCallBuffer *speaker; + + DRWShadingGroup *extra_wire; + DRWShadingGroup *extra_loose_points; +} OVERLAY_ExtraCallBuffers; + +typedef struct OVERLAY_ArmatureCallBuffersInner { + DRWCallBuffer *box_outline; + DRWCallBuffer *box_fill; + + DRWCallBuffer *dof_lines; + DRWCallBuffer *dof_sphere; + + DRWCallBuffer *envelope_distance; + DRWCallBuffer *envelope_outline; + DRWCallBuffer *envelope_fill; + + DRWCallBuffer *octa_outline; + DRWCallBuffer *octa_fill; + + DRWCallBuffer *point_outline; + DRWCallBuffer *point_fill; + + DRWCallBuffer *stick; + + DRWCallBuffer *wire; + + DRWShadingGroup *custom_outline; + DRWShadingGroup *custom_fill; + DRWShadingGroup *custom_wire; + + GHash *custom_shapes_ghash; +} OVERLAY_ArmatureCallBuffersInner; + +typedef struct OVERLAY_ArmatureCallBuffers { + OVERLAY_ArmatureCallBuffersInner solid; + OVERLAY_ArmatureCallBuffersInner transp; +} 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_gpencil_points_grp; + DRWShadingGroup *edit_gpencil_wires_grp; + DRWShadingGroup *edit_gpencil_curve_handle_grp; + DRWShadingGroup *edit_gpencil_curve_points_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_particle_strand_grp; + DRWShadingGroup *edit_particle_point_grp; + DRWShadingGroup *edit_text_cursor_grp; + DRWShadingGroup *edit_text_selection_grp; + DRWShadingGroup *edit_text_wire_grp[2]; + DRWShadingGroup *edit_uv_verts_grp; + DRWShadingGroup *edit_uv_edges_grp; + DRWShadingGroup *edit_uv_shadow_edges_grp; + DRWShadingGroup *edit_uv_faces_grp; + DRWShadingGroup *edit_uv_face_dots_grp; + DRWShadingGroup *edit_uv_stretching_grp; + DRWShadingGroup *edit_curves_points_grp[2]; + DRWShadingGroup *extra_grid_grp; + DRWShadingGroup *facing_grp[2]; + DRWShadingGroup *fade_grp[2]; + DRWShadingGroup *flash_grp[2]; + DRWShadingGroup *motion_path_lines_grp; + DRWShadingGroup *motion_path_points_grp; + DRWShadingGroup *outlines_grp; + DRWShadingGroup *outlines_curves_grp; + DRWShadingGroup *outlines_ptcloud_grp; + DRWShadingGroup *outlines_gpencil_grp; + DRWShadingGroup *paint_depth_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 *pointcloud_dots_grp; + DRWShadingGroup *sculpt_mask_grp; + DRWShadingGroup *sculpt_curves_selection_grp; + DRWShadingGroup *volume_selection_surface_grp; + DRWShadingGroup *wires_grp[2][2]; /* With and without coloring. */ + DRWShadingGroup *wires_all_grp[2][2]; /* With and without coloring. */ + DRWShadingGroup *wires_hair_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_edit_text; + DRWView *view_reference_images; + DRWView *view_edit_curves_points; + + /** TODO: get rid of this. */ + 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; + char space_type; + bool clear_in_front; + bool use_in_front; + bool wireframe_mode; + bool hide_overlays; + bool xray_enabled; + bool xray_enabled_and_not_wire; + float xray_opacity; + short v3d_flag; /* TODO: move to #View3DOverlay. */ + short v3d_gridflag; /* TODO: move to #View3DOverlay. */ + int cfra; + DRWState clipping_state; + OVERLAY_ShadingData shdata; + OVERLAY_GridData grid_data; + + struct { + float grid_axes[3]; + float zplane_axes[3]; + OVERLAY_GridBits zneg_flag, zpos_flag, grid_flag; + } grid; + struct { + bool enabled; + bool do_depth_copy; + bool do_depth_infront_copy; + } antialiasing; + struct { + bool show_handles; + int handle_display; + } edit_curve; + struct { + float cursor_color[4]; + float selection_color[4]; + } edit_text; + struct { + 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 do_zbufclip; + } edit_curves; + struct { + bool use_weight; + int select_mode; + } edit_particle; + struct { + bool do_uv_overlay; + bool do_uv_shadow_overlay; + bool do_uv_stretching_overlay; + bool do_tiled_image_overlay; + bool do_tiled_image_border_overlay; + bool do_stencil_overlay; + bool do_mask_overlay; + + bool do_verts; + bool do_faces; + bool do_face_dots; + + float uv_opacity; + + int image_size[2]; + float image_aspect[2]; + + /* edge drawing */ + OVERLAY_UVLineStyle line_style; + float dash_length; + int do_smooth_wire; + + /* stretching overlay */ + float uv_aspect[2]; + eSpaceImage_UVDT_Stretch draw_type; + ListBase totals; + float total_area_ratio; + + /* stencil overlay */ + struct Image *stencil_image; + struct ImBuf *stencil_ibuf; + void *stencil_lock; + + /* mask overlay */ + Mask *mask; + eMaskOverlayMode mask_overlay_mode; + GPUTexture *mask_texture; + } edit_uv; + struct { + bool transparent; + bool show_relations; + bool do_pose_xray; + bool do_pose_fade_geom; + } armature; + struct { + bool in_front; + bool alpha_blending; + } painting; + struct { + DRWCallBuffer *handle[2]; + } mball; + struct { + double time; + bool any_animated; + } mode_transfer; +} OVERLAY_PrivateData; /* Transient data */ + +typedef struct OVERLAY_StorageList { + struct OVERLAY_PrivateData *pd; +} OVERLAY_StorageList; + +typedef struct OVERLAY_Instance { + GPUUniformBuf *grid_ubo; +} OVERLAY_Instance; + +typedef struct OVERLAY_Data { + void *engine_type; + OVERLAY_FramebufferList *fbl; + OVERLAY_TextureList *txl; + OVERLAY_PassList *psl; + OVERLAY_StorageList *stl; + + OVERLAY_Instance *instance; +} 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; + struct GPUVertFormat *point_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_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); +void OVERLAY_xray_fade_draw(OVERLAY_Data *vedata); +void OVERLAY_xray_depth_copy(OVERLAY_Data *vedata); +void OVERLAY_xray_depth_infront_copy(OVERLAY_Data *vedata); + +/** + * Return true if armature should be handled by the pose mode engine. + */ +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_background_cache_init(OVERLAY_Data *vedata); +void OVERLAY_background_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_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_gpencil_cache_init(OVERLAY_Data *vedata); +void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata); +void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob); +void OVERLAY_gpencil_draw(OVERLAY_Data *vedata); +void OVERLAY_edit_gpencil_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_volume_cache_init(OVERLAY_Data *vedata); +void OVERLAY_volume_cache_populate(OVERLAY_Data *vedata, Object *ob); +void OVERLAY_volume_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_edit_uv_init(OVERLAY_Data *vedata); +void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata); +void OVERLAY_edit_uv_cache_finish(OVERLAY_Data *vedata); +void OVERLAY_edit_uv_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_blend_draw(OVERLAY_Data *vedata); +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_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_point(OVERLAY_ExtraCallBuffers *cb, const float point[3], const float color[4]); +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], + int color_id); +void OVERLAY_empty_shape(OVERLAY_ExtraCallBuffers *cb, + const float mat[4][4], + float draw_size, + 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_facing_infront_draw(OVERLAY_Data *vedata); + +void OVERLAY_fade_init(OVERLAY_Data *vedata); +void OVERLAY_fade_cache_init(OVERLAY_Data *vedata); +void OVERLAY_fade_cache_populate(OVERLAY_Data *vedata, Object *ob); +void OVERLAY_fade_draw(OVERLAY_Data *vedata); +void OVERLAY_fade_infront_draw(OVERLAY_Data *vedata); + +void OVERLAY_mode_transfer_cache_init(OVERLAY_Data *vedata); +void OVERLAY_mode_transfer_cache_populate(OVERLAY_Data *vedata, Object *ob); +void OVERLAY_mode_transfer_draw(OVERLAY_Data *vedata); +void OVERLAY_mode_transfer_infront_draw(OVERLAY_Data *vedata); +void OVERLAY_mode_transfer_cache_finish(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_background_draw(OVERLAY_Data *vedata); +/** + * This function draws images that needs the view transform applied. + * It draws these images directly into the scene color buffer. + */ +void OVERLAY_image_scene_background_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_init(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_sculpt_curves_cache_init(OVERLAY_Data *vedata); +void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *ob); +void OVERLAY_sculpt_curves_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); + +void OVERLAY_edit_curves_init(OVERLAY_Data *vedata); +void OVERLAY_edit_curves_cache_init(OVERLAY_Data *vedata); +void OVERLAY_edit_curves_cache_populate(OVERLAY_Data *vedata, Object *ob); +void OVERLAY_edit_curves_draw(OVERLAY_Data *vedata); + +GPUShader *OVERLAY_shader_antialiasing(void); +GPUShader *OVERLAY_shader_armature_degrees_of_freedom_wire(void); +GPUShader *OVERLAY_shader_armature_degrees_of_freedom_solid(void); +GPUShader *OVERLAY_shader_armature_envelope(bool use_outline); +GPUShader *OVERLAY_shader_armature_shape(bool use_outline); +GPUShader *OVERLAY_shader_armature_shape_wire(void); +GPUShader *OVERLAY_shader_armature_sphere(bool use_outline); +GPUShader *OVERLAY_shader_armature_stick(void); +GPUShader *OVERLAY_shader_armature_wire(void); +GPUShader *OVERLAY_shader_background(void); +GPUShader *OVERLAY_shader_clipbound(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_gpencil_guide_point(void); +GPUShader *OVERLAY_shader_edit_gpencil_point(void); +GPUShader *OVERLAY_shader_edit_gpencil_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_edit_uv_edges_get(void); +GPUShader *OVERLAY_shader_edit_uv_edges_for_edge_select_get(void); +GPUShader *OVERLAY_shader_edit_uv_face_get(void); +GPUShader *OVERLAY_shader_edit_uv_face_dots_get(void); +GPUShader *OVERLAY_shader_edit_uv_verts_get(void); +GPUShader *OVERLAY_shader_edit_uv_stretching_area_get(void); +GPUShader *OVERLAY_shader_edit_uv_stretching_angle_get(void); +GPUShader *OVERLAY_shader_edit_uv_tiled_image_borders_get(void); +GPUShader *OVERLAY_shader_edit_uv_stencil_image(void); +GPUShader *OVERLAY_shader_edit_uv_mask_image(void); +GPUShader *OVERLAY_shader_extra(bool is_select); +GPUShader *OVERLAY_shader_extra_groundline(void); +GPUShader *OVERLAY_shader_extra_wire(bool use_object, bool is_select); +GPUShader *OVERLAY_shader_extra_loose_point(void); +GPUShader *OVERLAY_shader_extra_point(void); +GPUShader *OVERLAY_shader_facing(void); +GPUShader *OVERLAY_shader_gpencil_canvas(void); +GPUShader *OVERLAY_shader_grid(void); +GPUShader *OVERLAY_shader_grid_background(void); +GPUShader *OVERLAY_shader_grid_image(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_curves(void); +GPUShader *OVERLAY_shader_outline_prepass_gpencil(void); +GPUShader *OVERLAY_shader_outline_prepass_pointcloud(void); +GPUShader *OVERLAY_shader_extra_grid(void); +GPUShader *OVERLAY_shader_outline_detect(void); +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(bool shading); +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_sculpt_curves_selection(void); +GPUShader *OVERLAY_shader_volume_velocity(bool use_needle, bool use_mac); +GPUShader *OVERLAY_shader_volume_gridlines(bool color_with_flags, bool color_range); +GPUShader *OVERLAY_shader_wireframe(bool custom_bias); +GPUShader *OVERLAY_shader_wireframe_select(void); +GPUShader *OVERLAY_shader_xray_fade(void); + +OVERLAY_InstanceFormats *OVERLAY_shader_instance_formats_get(void); + +void OVERLAY_shader_free(void); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/engines/overlay/overlay_sculpt.c b/source/blender/draw/engines/overlay/overlay_sculpt.c deleted file mode 100644 index 4a6477b3f6c..00000000000 --- a/source/blender/draw/engines/overlay/overlay_sculpt.c +++ /dev/null @@ -1,77 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "DRW_render.h" - -#include "draw_cache_impl.h" -#include "overlay_private.h" - -#include "BKE_paint.h" -#include "BKE_pbvh.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_MUL; - 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); - DRW_shgroup_uniform_float_copy( - grp, "faceSetsOpacity", pd->overlay.sculpt_mode_face_sets_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(); - struct GPUBatch *sculpt_overlays; - PBVH *pbvh = ob->sculpt->pbvh; - - const bool use_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); - - if (!pbvh) { - /* It is possible to have SculptSession without PBVH. This happens, for example, when toggling - * object mode to sculpt then to edit mode. */ - return; - } - - if (!pbvh_has_mask(pbvh) && !pbvh_has_face_sets(pbvh)) { - /* The SculptSession and the PBVH can be created without a Mask data-layer or Face Set - * data-layer. (masks data-layers are created after using a mask tool), so in these cases there - * is nothing to draw. */ - return; - } - - if (use_pbvh) { - DRW_shgroup_call_sculpt(pd->sculpt_mask_grp, ob, false, true); - } - else { - sculpt_overlays = DRW_mesh_batch_cache_get_sculpt_overlays(ob->data); - if (sculpt_overlays) { - DRW_shgroup_call(pd->sculpt_mask_grp, sculpt_overlays, ob); - } - } -} - -void OVERLAY_sculpt_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_PrivateData *pd = vedata->stl->pd; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(pd->painting.in_front ? dfbl->in_front_fb : dfbl->default_fb); - } - - DRW_draw_pass(psl->sculpt_mask_ps); -} diff --git a/source/blender/draw/engines/overlay/overlay_sculpt.cc b/source/blender/draw/engines/overlay/overlay_sculpt.cc new file mode 100644 index 00000000000..ddad1f06537 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_sculpt.cc @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "draw_cache_impl.h" +#include "overlay_private.hh" + +#include "BKE_paint.h" +#include "BKE_pbvh.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_MUL; + 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); + DRW_shgroup_uniform_float_copy( + grp, "faceSetsOpacity", pd->overlay.sculpt_mode_face_sets_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(); + struct GPUBatch *sculpt_overlays; + PBVH *pbvh = ob->sculpt->pbvh; + + const bool use_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); + + if (!pbvh) { + /* It is possible to have SculptSession without PBVH. This happens, for example, when toggling + * object mode to sculpt then to edit mode. */ + return; + } + + if (!pbvh_has_mask(pbvh) && !pbvh_has_face_sets(pbvh)) { + /* The SculptSession and the PBVH can be created without a Mask data-layer or Face Set + * data-layer. (masks data-layers are created after using a mask tool), so in these cases there + * is nothing to draw. */ + return; + } + + if (use_pbvh) { + DRW_shgroup_call_sculpt(pd->sculpt_mask_grp, ob, false, true); + } + else { + sculpt_overlays = DRW_mesh_batch_cache_get_sculpt_overlays(static_cast(ob->data)); + if (sculpt_overlays) { + DRW_shgroup_call(pd->sculpt_mask_grp, sculpt_overlays, ob); + } + } +} + +void OVERLAY_sculpt_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(pd->painting.in_front ? dfbl->in_front_fb : dfbl->default_fb); + } + + DRW_draw_pass(psl->sculpt_mask_ps); +} diff --git a/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc b/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc index b8021124f27..1bba2a366a5 100644 --- a/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc +++ b/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc @@ -8,7 +8,7 @@ #include "DRW_render.h" #include "draw_cache_impl.h" -#include "overlay_private.h" +#include "overlay_private.hh" #include "BKE_curves.hh" diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c deleted file mode 100644 index 2373363ab9d..00000000000 --- a/source/blender/draw/engines/overlay/overlay_shader.c +++ /dev/null @@ -1,1082 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "DRW_render.h" - -#include "GPU_shader.h" - -#include "UI_resources.h" - -#include "overlay_private.h" - -typedef struct OVERLAY_Shaders { - GPUShader *antialiasing; - GPUShader *armature_dof_wire; - GPUShader *armature_dof_solid; - GPUShader *armature_envelope_outline; - GPUShader *armature_envelope_solid; - GPUShader *armature_shape_outline; - GPUShader *armature_shape_solid; - GPUShader *armature_shape_wire; - GPUShader *armature_sphere_outline; - GPUShader *armature_sphere_solid; - GPUShader *armature_stick; - GPUShader *armature_wire; - GPUShader *background; - GPUShader *clipbound; - GPUShader *depth_only; - GPUShader *edit_curve_handle; - GPUShader *edit_curve_point; - GPUShader *edit_curve_wire; - GPUShader *edit_gpencil_guide_point; - GPUShader *edit_gpencil_point; - GPUShader *edit_gpencil_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 *edit_uv_verts; - GPUShader *edit_uv_faces; - GPUShader *edit_uv_edges; - GPUShader *edit_uv_edges_for_edge_select; - GPUShader *edit_uv_face_dots; - GPUShader *edit_uv_stretching_angle; - GPUShader *edit_uv_stretching_area; - GPUShader *edit_uv_tiled_image_borders; - GPUShader *edit_uv_stencil_image; - GPUShader *edit_uv_mask_image; - GPUShader *extra; - GPUShader *extra_select; - GPUShader *extra_groundline; - GPUShader *extra_wire[2]; - GPUShader *extra_wire_select; - GPUShader *extra_point; - GPUShader *extra_lightprobe_grid; - GPUShader *extra_loose_point; - GPUShader *facing; - GPUShader *gpencil_canvas; - GPUShader *grid; - GPUShader *grid_background; - GPUShader *grid_image; - GPUShader *image; - GPUShader *motion_path_line; - GPUShader *motion_path_vert; - GPUShader *outline_prepass; - GPUShader *outline_prepass_curves; - GPUShader *outline_prepass_gpencil; - GPUShader *outline_prepass_pointcloud; - GPUShader *outline_prepass_wire; - GPUShader *outline_detect; - GPUShader *paint_face; - GPUShader *paint_point; - GPUShader *paint_texture; - GPUShader *paint_vertcol; - GPUShader *paint_weight[2]; - GPUShader *paint_wire; - GPUShader *particle_dot; - GPUShader *particle_shape; - GPUShader *pointcloud_dot; - GPUShader *sculpt_mask; - GPUShader *sculpt_curves_selection; - GPUShader *uniform_color; - GPUShader *volume_velocity_needle_sh; - GPUShader *volume_velocity_mac_sh; - GPUShader *volume_velocity_sh; - GPUShader *volume_gridlines_sh; - GPUShader *volume_gridlines_flags_sh; - GPUShader *volume_gridlines_range_sh; - GPUShader *wireframe_select; - GPUShader *wireframe[2]; - GPUShader *xray_fade; -} 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_info_name("overlay_antialiasing"); - } - return sh_data->antialiasing; -} - -GPUShader *OVERLAY_shader_background(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->background) { - sh_data->background = GPU_shader_create_from_info_name("overlay_background"); - } - return sh_data->background; -} - -GPUShader *OVERLAY_shader_clipbound(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->clipbound) { - sh_data->clipbound = GPU_shader_create_from_info_name("overlay_clipbound"); - } - return sh_data->clipbound; -} - -GPUShader *OVERLAY_shader_depth_only(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_depth_only_clipped" : "overlay_depth_only"); - } - return sh_data->depth_only; -} - -GPUShader *OVERLAY_shader_edit_mesh_vert(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_edit_mesh_vert_clipped" : "overlay_edit_mesh_vert"); - } - return sh_data->edit_mesh_vert; -} - -GPUShader *OVERLAY_shader_edit_mesh_edge(bool use_flat_interp) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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) { - *sh = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? - (use_flat_interp ? "overlay_edit_mesh_edge_flat_clipped" : - "overlay_edit_mesh_edge_clipped") : - (use_flat_interp ? "overlay_edit_mesh_edge_flat" : "overlay_edit_mesh_edge")); - } - return *sh; -} - -GPUShader *OVERLAY_shader_armature_sphere(bool use_outline) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (use_outline && !sh_data->armature_sphere_outline) { - sh_data->armature_sphere_outline = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_armature_sphere_outline_clipped" : - "overlay_armature_sphere_outline"); - } - else if (!sh_data->armature_sphere_solid) { - sh_data->armature_sphere_solid = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_armature_sphere_solid_clipped" : - "overlay_armature_sphere_solid"); - } - 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(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_armature_shape_outline_clipped" : - "overlay_armature_shape_outline"); - } - else if (!sh_data->armature_shape_solid) { - sh_data->armature_shape_solid = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_armature_shape_solid_clipped" : - "overlay_armature_shape_solid"); - } - return use_outline ? sh_data->armature_shape_outline : sh_data->armature_shape_solid; -} - -GPUShader *OVERLAY_shader_armature_shape_wire(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->armature_shape_wire) { - sh_data->armature_shape_wire = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_armature_shape_wire_clipped" : "overlay_armature_shape_wire"); - } - return sh_data->armature_shape_wire; -} - -GPUShader *OVERLAY_shader_armature_envelope(bool use_outline) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_armature_envelope_outline_clipped" : - "overlay_armature_envelope_outline"); - } - else if (!sh_data->armature_envelope_solid) { - sh_data->armature_envelope_solid = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_armature_envelope_solid_clipped" : - "overlay_armature_envelope_solid"); - } - 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(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_armature_stick_clipped" : "overlay_armature_stick"); - } - return sh_data->armature_stick; -} - -GPUShader *OVERLAY_shader_armature_degrees_of_freedom_wire(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->armature_dof_wire) { - sh_data->armature_dof_wire = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_armature_dof_wire_clipped" : "overlay_armature_dof_wire"); - } - return sh_data->armature_dof_wire; -} - -GPUShader *OVERLAY_shader_armature_degrees_of_freedom_solid(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->armature_dof_solid) { - sh_data->armature_dof_solid = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_armature_dof_solid_clipped" : "overlay_armature_dof_solid"); - } - return sh_data->armature_dof_solid; -} - -GPUShader *OVERLAY_shader_armature_wire(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_armature_wire_clipped" : "overlay_armature_wire"); - } - return sh_data->armature_wire; -} - -GPUShader *OVERLAY_shader_edit_curve_handle(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_edit_curve_handle_clipped" : "overlay_edit_curve_handle"); - } - return sh_data->edit_curve_handle; -} - -GPUShader *OVERLAY_shader_edit_curve_point(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_edit_curve_point_clipped" : "overlay_edit_curve_point"); - } - return sh_data->edit_curve_point; -} - -GPUShader *OVERLAY_shader_edit_curve_wire(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_edit_curve_wire_clipped" : "overlay_edit_curve_wire"); - } - return sh_data->edit_curve_wire; -} - -GPUShader *OVERLAY_shader_edit_gpencil_guide_point(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->edit_gpencil_guide_point) { - sh_data->edit_gpencil_guide_point = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_edit_gpencil_guide_point_clipped" : - "overlay_edit_gpencil_guide_point"); - } - return sh_data->edit_gpencil_guide_point; -} - -GPUShader *OVERLAY_shader_edit_gpencil_point(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->edit_gpencil_point) { - sh_data->edit_gpencil_point = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_edit_gpencil_point_clipped" : "overlay_edit_gpencil_point"); - } - return sh_data->edit_gpencil_point; -} - -GPUShader *OVERLAY_shader_edit_gpencil_wire(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->edit_gpencil_wire) { - sh_data->edit_gpencil_wire = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_edit_gpencil_wire_clipped" : "overlay_edit_gpencil_wire"); - } - return sh_data->edit_gpencil_wire; -} - -GPUShader *OVERLAY_shader_edit_lattice_point(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_edit_lattice_point_clipped" : "overlay_edit_lattice_point"); - } - return sh_data->edit_lattice_point; -} - -GPUShader *OVERLAY_shader_edit_lattice_wire(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_edit_lattice_wire_clipped" : "overlay_edit_lattice_wire"); - } - return sh_data->edit_lattice_wire; -} - -GPUShader *OVERLAY_shader_edit_mesh_face(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_edit_mesh_face_clipped" : "overlay_edit_mesh_face"); - } - return sh_data->edit_mesh_face; -} - -GPUShader *OVERLAY_shader_edit_mesh_facedot(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_edit_mesh_facedot_clipped" : "overlay_edit_mesh_facedot"); - } - return sh_data->edit_mesh_facedot; -} - -GPUShader *OVERLAY_shader_edit_mesh_normal(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_edit_mesh_normal_clipped" : "overlay_edit_mesh_normal"); - } - return sh_data->edit_mesh_normals; -} - -GPUShader *OVERLAY_shader_edit_mesh_analysis(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_edit_mesh_analysis_clipped" : "overlay_edit_mesh_analysis"); - } - return sh_data->edit_mesh_analysis; -} - -GPUShader *OVERLAY_shader_edit_mesh_skin_root(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_edit_mesh_skin_root_clipped" : "overlay_edit_mesh_skin_root"); - } - return sh_data->edit_mesh_skin_root; -} - -GPUShader *OVERLAY_shader_edit_particle_strand(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_edit_particle_strand_clipped" : - "overlay_edit_particle_strand"); - } - return sh_data->edit_particle_strand; -} - -GPUShader *OVERLAY_shader_edit_particle_point(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_edit_particle_point_clipped" : "overlay_edit_particle_point"); - } - return sh_data->edit_particle_point; -} - -GPUShader *OVERLAY_shader_extra(bool is_select) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - GPUShader **sh = (is_select) ? &sh_data->extra_select : &sh_data->extra; - if (!*sh) { - *sh = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? (is_select ? "overlay_extra_select_clipped" : "overlay_extra_clipped") : - (is_select ? "overlay_extra_select" : "overlay_extra")); - } - return *sh; -} - -GPUShader *OVERLAY_shader_extra_grid(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->extra_lightprobe_grid) { - sh_data->extra_lightprobe_grid = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_extra_grid_clipped" : "overlay_extra_grid"); - } - return sh_data->extra_lightprobe_grid; -} - -GPUShader *OVERLAY_shader_extra_groundline(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_extra_groundline_clipped" : "overlay_extra_groundline"); - } - return sh_data->extra_groundline; -} - -GPUShader *OVERLAY_shader_extra_wire(bool use_object, bool is_select) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - GPUShader **sh = (is_select) ? &sh_data->extra_wire_select : &sh_data->extra_wire[use_object]; - if (!*sh) { - const char *info_name = NULL; - if (draw_ctx->sh_cfg) { - if (is_select) { - info_name = "overlay_extra_wire_select_clipped"; - } - else { - info_name = use_object ? "overlay_extra_wire_object_clipped" : - "overlay_extra_wire_clipped"; - } - } - else { - if (is_select) { - info_name = "overlay_extra_wire_select"; - } - else { - info_name = use_object ? "overlay_extra_wire_object" : "overlay_extra_wire"; - } - } - *sh = GPU_shader_create_from_info_name(info_name); - } - return *sh; -} - -GPUShader *OVERLAY_shader_extra_loose_point(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_extra_loose_point_clipped" : "overlay_extra_loose_point"); - } - return sh_data->extra_loose_point; -} - -GPUShader *OVERLAY_shader_extra_point(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_extra_point_clipped" : "overlay_extra_point"); - } - return sh_data->extra_point; -} - -GPUShader *OVERLAY_shader_facing(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->facing) { - sh_data->facing = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_facing_clipped" : "overlay_facing"); - } - return sh_data->facing; -} - -GPUShader *OVERLAY_shader_gpencil_canvas(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->gpencil_canvas) { - /* TODO(fclem): Support Clipping? Everything is already setup but don't want to change behavior - * without agreement of all gpencil module. */ - sh_data->gpencil_canvas = GPU_shader_create_from_info_name( - 0 ? "overlay_gpencil_canvas_clipped" : "overlay_gpencil_canvas"); - } - return sh_data->gpencil_canvas; -} - -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_info_name("overlay_grid"); - } - return sh_data->grid; -} - -GPUShader *OVERLAY_shader_grid_background(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->grid_background) { - sh_data->grid_background = GPU_shader_create_from_info_name("overlay_grid_background"); - } - return sh_data->grid_background; -} - -GPUShader *OVERLAY_shader_grid_image(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->grid_image) { - sh_data->grid_image = GPU_shader_create_from_info_name("overlay_grid_image"); - } - return sh_data->grid_image; -} - -GPUShader *OVERLAY_shader_edit_uv_stencil_image(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->edit_uv_stencil_image) { - sh_data->edit_uv_stencil_image = GPU_shader_create_from_info_name( - "overlay_edit_uv_stencil_image"); - } - return sh_data->edit_uv_stencil_image; -} - -GPUShader *OVERLAY_shader_edit_uv_mask_image(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->edit_uv_mask_image) { - sh_data->edit_uv_mask_image = GPU_shader_create_from_info_name("overlay_edit_uv_mask_image"); - } - return sh_data->edit_uv_mask_image; -} - -GPUShader *OVERLAY_shader_image(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->image) { - /* TODO(fclem): Do we want to allow clipping reference images? */ - sh_data->image = GPU_shader_create_from_info_name(0 ? "overlay_image_clipped" : - "overlay_image"); - } - return sh_data->image; -} - -GPUShader *OVERLAY_shader_motion_path_line(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_motion_path_line_clipped" : "overlay_motion_path_line"); - } - return sh_data->motion_path_line; -} - -GPUShader *OVERLAY_shader_motion_path_vert(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_motion_path_point_clipped" : "overlay_motion_path_point"); - } - return sh_data->motion_path_vert; -} - -GPUShader *OVERLAY_shader_outline_prepass(bool use_wire) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_outline_prepass_wire_clipped" : - "overlay_outline_prepass_wire"); - } - else if (!sh_data->outline_prepass) { - sh_data->outline_prepass = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_outline_prepass_mesh_clipped" : - "overlay_outline_prepass_mesh"); - } - return use_wire ? sh_data->outline_prepass_wire : sh_data->outline_prepass; -} - -GPUShader *OVERLAY_shader_outline_prepass_curves() -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->outline_prepass_curves) { - sh_data->outline_prepass_curves = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_outline_prepass_curves_clipped" : - "overlay_outline_prepass_curves"); - } - return sh_data->outline_prepass_curves; -} - -GPUShader *OVERLAY_shader_outline_prepass_gpencil(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->outline_prepass_gpencil) { - sh_data->outline_prepass_gpencil = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_outline_prepass_gpencil_clipped" : - "overlay_outline_prepass_gpencil"); - } - return sh_data->outline_prepass_gpencil; -} - -GPUShader *OVERLAY_shader_outline_prepass_pointcloud(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->outline_prepass_pointcloud) { - sh_data->outline_prepass_pointcloud = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg ? "overlay_outline_prepass_pointcloud_clipped" : - "overlay_outline_prepass_pointcloud"); - } - return sh_data->outline_prepass_pointcloud; -} - -GPUShader *OVERLAY_shader_outline_detect(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->outline_detect) { - sh_data->outline_detect = GPU_shader_create_from_info_name("overlay_outline_detect"); - } - return sh_data->outline_detect; -} - -GPUShader *OVERLAY_shader_paint_face(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg; - OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - if (!sh_data->paint_face) { - sh_data->paint_face = GPU_shader_create_from_info_name( - sh_cfg == GPU_SHADER_CFG_CLIPPED ? "overlay_paint_face_clipped" : "overlay_paint_face"); - } - return sh_data->paint_face; -} - -GPUShader *OVERLAY_shader_paint_point(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg; - OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - if (!sh_data->paint_point) { - sh_data->paint_point = GPU_shader_create_from_info_name( - sh_cfg == GPU_SHADER_CFG_CLIPPED ? "overlay_paint_point_clipped" : "overlay_paint_point"); - } - return sh_data->paint_point; -} - -GPUShader *OVERLAY_shader_paint_texture(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg; - OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - if (!sh_data->paint_texture) { - sh_data->paint_texture = GPU_shader_create_from_info_name( - sh_cfg ? "overlay_paint_texture_clipped" : "overlay_paint_texture"); - } - return sh_data->paint_texture; -} - -GPUShader *OVERLAY_shader_paint_vertcol(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg; - OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - if (!sh_data->paint_vertcol) { - sh_data->paint_vertcol = GPU_shader_create_from_info_name( - sh_cfg ? "overlay_paint_vertcol_clipped" : "overlay_paint_vertcol"); - } - return sh_data->paint_vertcol; -} - -GPUShader *OVERLAY_shader_paint_weight(const bool shading) -{ - const char *info_name[2][2] = { - {"overlay_paint_weight", "overlay_paint_weight_fake_shading"}, - {"overlay_paint_weight_clipped", "overlay_paint_weight_fake_shading_clipped"}, - }; - int index = shading ? 1 : 0; - const DRWContextState *draw_ctx = DRW_context_state_get(); - eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg; - OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - if (!sh_data->paint_weight[index]) { - sh_data->paint_weight[index] = GPU_shader_create_from_info_name(info_name[sh_cfg][index]); - } - return sh_data->paint_weight[index]; -} - -GPUShader *OVERLAY_shader_paint_wire(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg; - OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - if (!sh_data->paint_wire) { - sh_data->paint_wire = GPU_shader_create_from_info_name(sh_cfg ? "overlay_paint_wire_clipped" : - "overlay_paint_wire"); - } - return sh_data->paint_wire; -} - -GPUShader *OVERLAY_shader_particle_dot(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_particle_dot_clipped" : "overlay_particle_dot"); - } - return sh_data->particle_dot; -} - -GPUShader *OVERLAY_shader_particle_shape(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_particle_shape_clipped" : "overlay_particle_shape"); - } - return sh_data->particle_shape; -} - -GPUShader *OVERLAY_shader_sculpt_mask(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_sculpt_mask_clipped" : "overlay_sculpt_mask"); - } - return sh_data->sculpt_mask; -} - -GPUShader *OVERLAY_shader_sculpt_curves_selection(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->sculpt_curves_selection) { - sh_data->sculpt_curves_selection = GPU_shader_create_from_info_name( - draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED ? "overlay_sculpt_curves_selection_clipped" : - "overlay_sculpt_curves_selection"); - } - return sh_data->sculpt_curves_selection; -} - -struct GPUShader *OVERLAY_shader_uniform_color(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_uniform_color_clipped" : "overlay_uniform_color"); - } - return sh_data->uniform_color; -} - -struct GPUShader *OVERLAY_shader_volume_velocity(bool use_needle, bool use_mac) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (use_needle && !sh_data->volume_velocity_needle_sh) { - sh_data->volume_velocity_needle_sh = GPU_shader_create_from_info_name( - "overlay_volume_velocity_needle"); - } - else if (use_mac && !sh_data->volume_velocity_mac_sh) { - sh_data->volume_velocity_mac_sh = GPU_shader_create_from_info_name( - "overlay_volume_velocity_mac"); - } - else if (!sh_data->volume_velocity_sh) { - sh_data->volume_velocity_sh = GPU_shader_create_from_info_name("overlay_volume_velocity"); - } - - if (use_needle) { - return sh_data->volume_velocity_needle_sh; - } - if (use_mac) { - return sh_data->volume_velocity_mac_sh; - } - return sh_data->volume_velocity_sh; -} - -struct GPUShader *OVERLAY_shader_volume_gridlines(bool color_with_flags, bool color_range) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->volume_gridlines_flags_sh && color_with_flags) { - sh_data->volume_gridlines_flags_sh = GPU_shader_create_from_info_name( - "overlay_volume_gridlines_flags"); - } - else if (!sh_data->volume_gridlines_range_sh && color_range) { - sh_data->volume_gridlines_range_sh = GPU_shader_create_from_info_name( - "overlay_volume_gridlines_range"); - } - else if (!sh_data->volume_gridlines_sh) { - sh_data->volume_gridlines_sh = GPU_shader_create_from_info_name("overlay_volume_gridlines"); - } - - if (color_with_flags) { - return sh_data->volume_gridlines_flags_sh; - } - if (color_range) { - return sh_data->volume_gridlines_range_sh; - } - - return sh_data->volume_gridlines_sh; -} - -GPUShader *OVERLAY_shader_wireframe_select(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - 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_info_name( - draw_ctx->sh_cfg ? "overlay_wireframe_select_clipped" : "overlay_wireframe_select"); - } - return sh_data->wireframe_select; -} - -GPUShader *OVERLAY_shader_wireframe(bool custom_bias) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->wireframe[custom_bias]) { - sh_data->wireframe[custom_bias] = GPU_shader_create_from_info_name( - custom_bias ? (draw_ctx->sh_cfg ? "overlay_wireframe_custom_depth_clipped" : - "overlay_wireframe_custom_depth") : - (draw_ctx->sh_cfg ? "overlay_wireframe_clipped" : "overlay_wireframe")); - } - return sh_data->wireframe[custom_bias]; -} - -GPUShader *OVERLAY_shader_xray_fade(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->xray_fade) { - sh_data->xray_fade = GPU_shader_create_from_info_name("overlay_xray_fade"); - } - return sh_data->xray_fade; -} - -/* -------------------------------------------------------------------- */ -/** \name Edit UV shaders - * \{ */ - -GPUShader *OVERLAY_shader_edit_uv_edges_get(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->edit_uv_edges) { - sh_data->edit_uv_edges = GPU_shader_create_from_info_name("overlay_edit_uv_edges"); - } - return sh_data->edit_uv_edges; -} - -GPUShader *OVERLAY_shader_edit_uv_edges_for_edge_select_get(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->edit_uv_edges_for_edge_select) { - sh_data->edit_uv_edges_for_edge_select = GPU_shader_create_from_info_name( - "overlay_edit_uv_edges_select"); - } - return sh_data->edit_uv_edges_for_edge_select; -} - -GPUShader *OVERLAY_shader_edit_uv_face_get(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->edit_uv_faces) { - sh_data->edit_uv_faces = GPU_shader_create_from_info_name("overlay_edit_uv_faces"); - } - return sh_data->edit_uv_faces; -} - -GPUShader *OVERLAY_shader_edit_uv_face_dots_get(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->edit_uv_face_dots) { - sh_data->edit_uv_face_dots = GPU_shader_create_from_info_name("overlay_edit_uv_face_dots"); - } - return sh_data->edit_uv_face_dots; -} - -GPUShader *OVERLAY_shader_edit_uv_verts_get(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->edit_uv_verts) { - sh_data->edit_uv_verts = GPU_shader_create_from_info_name("overlay_edit_uv_verts"); - } - - return sh_data->edit_uv_verts; -} - -GPUShader *OVERLAY_shader_edit_uv_stretching_area_get(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->edit_uv_stretching_area) { - sh_data->edit_uv_stretching_area = GPU_shader_create_from_info_name( - "overlay_edit_uv_stretching_area"); - } - - return sh_data->edit_uv_stretching_area; -} - -GPUShader *OVERLAY_shader_edit_uv_stretching_angle_get(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->edit_uv_stretching_angle) { - sh_data->edit_uv_stretching_angle = GPU_shader_create_from_info_name( - "overlay_edit_uv_stretching_angle"); - } - - return sh_data->edit_uv_stretching_angle; -} - -GPUShader *OVERLAY_shader_edit_uv_tiled_image_borders_get(void) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->edit_uv_tiled_image_borders) { - sh_data->edit_uv_tiled_image_borders = GPU_shader_create_from_info_name( - "overlay_edit_uv_tiled_image_borders"); - } - return sh_data->edit_uv_tiled_image_borders; -} - -/** \} */ - -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.point_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); - } -} diff --git a/source/blender/draw/engines/overlay/overlay_shader.cc b/source/blender/draw/engines/overlay/overlay_shader.cc new file mode 100644 index 00000000000..b0a6926a57f --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_shader.cc @@ -0,0 +1,1082 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "GPU_shader.h" + +#include "UI_resources.h" + +#include "overlay_private.hh" + +typedef struct OVERLAY_Shaders { + GPUShader *antialiasing; + GPUShader *armature_dof_wire; + GPUShader *armature_dof_solid; + GPUShader *armature_envelope_outline; + GPUShader *armature_envelope_solid; + GPUShader *armature_shape_outline; + GPUShader *armature_shape_solid; + GPUShader *armature_shape_wire; + GPUShader *armature_sphere_outline; + GPUShader *armature_sphere_solid; + GPUShader *armature_stick; + GPUShader *armature_wire; + GPUShader *background; + GPUShader *clipbound; + GPUShader *depth_only; + GPUShader *edit_curve_handle; + GPUShader *edit_curve_point; + GPUShader *edit_curve_wire; + GPUShader *edit_gpencil_guide_point; + GPUShader *edit_gpencil_point; + GPUShader *edit_gpencil_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 *edit_uv_verts; + GPUShader *edit_uv_faces; + GPUShader *edit_uv_edges; + GPUShader *edit_uv_edges_for_edge_select; + GPUShader *edit_uv_face_dots; + GPUShader *edit_uv_stretching_angle; + GPUShader *edit_uv_stretching_area; + GPUShader *edit_uv_tiled_image_borders; + GPUShader *edit_uv_stencil_image; + GPUShader *edit_uv_mask_image; + GPUShader *extra; + GPUShader *extra_select; + GPUShader *extra_groundline; + GPUShader *extra_wire[2]; + GPUShader *extra_wire_select; + GPUShader *extra_point; + GPUShader *extra_lightprobe_grid; + GPUShader *extra_loose_point; + GPUShader *facing; + GPUShader *gpencil_canvas; + GPUShader *grid; + GPUShader *grid_background; + GPUShader *grid_image; + GPUShader *image; + GPUShader *motion_path_line; + GPUShader *motion_path_vert; + GPUShader *outline_prepass; + GPUShader *outline_prepass_curves; + GPUShader *outline_prepass_gpencil; + GPUShader *outline_prepass_pointcloud; + GPUShader *outline_prepass_wire; + GPUShader *outline_detect; + GPUShader *paint_face; + GPUShader *paint_point; + GPUShader *paint_texture; + GPUShader *paint_vertcol; + GPUShader *paint_weight[2]; + GPUShader *paint_wire; + GPUShader *particle_dot; + GPUShader *particle_shape; + GPUShader *pointcloud_dot; + GPUShader *sculpt_mask; + GPUShader *sculpt_curves_selection; + GPUShader *uniform_color; + GPUShader *volume_velocity_needle_sh; + GPUShader *volume_velocity_mac_sh; + GPUShader *volume_velocity_sh; + GPUShader *volume_gridlines_sh; + GPUShader *volume_gridlines_flags_sh; + GPUShader *volume_gridlines_range_sh; + GPUShader *wireframe_select; + GPUShader *wireframe[2]; + GPUShader *xray_fade; +} OVERLAY_Shaders; + +static struct { + OVERLAY_Shaders sh_data[GPU_SHADER_CFG_LEN]; +} e_data = {{{nullptr}}}; + +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_info_name("overlay_antialiasing"); + } + return sh_data->antialiasing; +} + +GPUShader *OVERLAY_shader_background(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->background) { + sh_data->background = GPU_shader_create_from_info_name("overlay_background"); + } + return sh_data->background; +} + +GPUShader *OVERLAY_shader_clipbound(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->clipbound) { + sh_data->clipbound = GPU_shader_create_from_info_name("overlay_clipbound"); + } + return sh_data->clipbound; +} + +GPUShader *OVERLAY_shader_depth_only(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_depth_only_clipped" : "overlay_depth_only"); + } + return sh_data->depth_only; +} + +GPUShader *OVERLAY_shader_edit_mesh_vert(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_edit_mesh_vert_clipped" : "overlay_edit_mesh_vert"); + } + return sh_data->edit_mesh_vert; +} + +GPUShader *OVERLAY_shader_edit_mesh_edge(bool use_flat_interp) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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 == nullptr) { + *sh = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? + (use_flat_interp ? "overlay_edit_mesh_edge_flat_clipped" : + "overlay_edit_mesh_edge_clipped") : + (use_flat_interp ? "overlay_edit_mesh_edge_flat" : "overlay_edit_mesh_edge")); + } + return *sh; +} + +GPUShader *OVERLAY_shader_armature_sphere(bool use_outline) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (use_outline && !sh_data->armature_sphere_outline) { + sh_data->armature_sphere_outline = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_armature_sphere_outline_clipped" : + "overlay_armature_sphere_outline"); + } + else if (!sh_data->armature_sphere_solid) { + sh_data->armature_sphere_solid = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_armature_sphere_solid_clipped" : + "overlay_armature_sphere_solid"); + } + 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(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_armature_shape_outline_clipped" : + "overlay_armature_shape_outline"); + } + else if (!sh_data->armature_shape_solid) { + sh_data->armature_shape_solid = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_armature_shape_solid_clipped" : + "overlay_armature_shape_solid"); + } + return use_outline ? sh_data->armature_shape_outline : sh_data->armature_shape_solid; +} + +GPUShader *OVERLAY_shader_armature_shape_wire(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->armature_shape_wire) { + sh_data->armature_shape_wire = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_armature_shape_wire_clipped" : "overlay_armature_shape_wire"); + } + return sh_data->armature_shape_wire; +} + +GPUShader *OVERLAY_shader_armature_envelope(bool use_outline) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_armature_envelope_outline_clipped" : + "overlay_armature_envelope_outline"); + } + else if (!sh_data->armature_envelope_solid) { + sh_data->armature_envelope_solid = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_armature_envelope_solid_clipped" : + "overlay_armature_envelope_solid"); + } + 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(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_armature_stick_clipped" : "overlay_armature_stick"); + } + return sh_data->armature_stick; +} + +GPUShader *OVERLAY_shader_armature_degrees_of_freedom_wire(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->armature_dof_wire) { + sh_data->armature_dof_wire = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_armature_dof_wire_clipped" : "overlay_armature_dof_wire"); + } + return sh_data->armature_dof_wire; +} + +GPUShader *OVERLAY_shader_armature_degrees_of_freedom_solid(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->armature_dof_solid) { + sh_data->armature_dof_solid = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_armature_dof_solid_clipped" : "overlay_armature_dof_solid"); + } + return sh_data->armature_dof_solid; +} + +GPUShader *OVERLAY_shader_armature_wire(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_armature_wire_clipped" : "overlay_armature_wire"); + } + return sh_data->armature_wire; +} + +GPUShader *OVERLAY_shader_edit_curve_handle(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_edit_curve_handle_clipped" : "overlay_edit_curve_handle"); + } + return sh_data->edit_curve_handle; +} + +GPUShader *OVERLAY_shader_edit_curve_point(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_edit_curve_point_clipped" : "overlay_edit_curve_point"); + } + return sh_data->edit_curve_point; +} + +GPUShader *OVERLAY_shader_edit_curve_wire(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_edit_curve_wire_clipped" : "overlay_edit_curve_wire"); + } + return sh_data->edit_curve_wire; +} + +GPUShader *OVERLAY_shader_edit_gpencil_guide_point(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->edit_gpencil_guide_point) { + sh_data->edit_gpencil_guide_point = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_edit_gpencil_guide_point_clipped" : + "overlay_edit_gpencil_guide_point"); + } + return sh_data->edit_gpencil_guide_point; +} + +GPUShader *OVERLAY_shader_edit_gpencil_point(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->edit_gpencil_point) { + sh_data->edit_gpencil_point = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_edit_gpencil_point_clipped" : "overlay_edit_gpencil_point"); + } + return sh_data->edit_gpencil_point; +} + +GPUShader *OVERLAY_shader_edit_gpencil_wire(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->edit_gpencil_wire) { + sh_data->edit_gpencil_wire = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_edit_gpencil_wire_clipped" : "overlay_edit_gpencil_wire"); + } + return sh_data->edit_gpencil_wire; +} + +GPUShader *OVERLAY_shader_edit_lattice_point(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_edit_lattice_point_clipped" : "overlay_edit_lattice_point"); + } + return sh_data->edit_lattice_point; +} + +GPUShader *OVERLAY_shader_edit_lattice_wire(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_edit_lattice_wire_clipped" : "overlay_edit_lattice_wire"); + } + return sh_data->edit_lattice_wire; +} + +GPUShader *OVERLAY_shader_edit_mesh_face(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_edit_mesh_face_clipped" : "overlay_edit_mesh_face"); + } + return sh_data->edit_mesh_face; +} + +GPUShader *OVERLAY_shader_edit_mesh_facedot(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_edit_mesh_facedot_clipped" : "overlay_edit_mesh_facedot"); + } + return sh_data->edit_mesh_facedot; +} + +GPUShader *OVERLAY_shader_edit_mesh_normal(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_edit_mesh_normal_clipped" : "overlay_edit_mesh_normal"); + } + return sh_data->edit_mesh_normals; +} + +GPUShader *OVERLAY_shader_edit_mesh_analysis(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_edit_mesh_analysis_clipped" : "overlay_edit_mesh_analysis"); + } + return sh_data->edit_mesh_analysis; +} + +GPUShader *OVERLAY_shader_edit_mesh_skin_root(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_edit_mesh_skin_root_clipped" : "overlay_edit_mesh_skin_root"); + } + return sh_data->edit_mesh_skin_root; +} + +GPUShader *OVERLAY_shader_edit_particle_strand(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_edit_particle_strand_clipped" : + "overlay_edit_particle_strand"); + } + return sh_data->edit_particle_strand; +} + +GPUShader *OVERLAY_shader_edit_particle_point(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_edit_particle_point_clipped" : "overlay_edit_particle_point"); + } + return sh_data->edit_particle_point; +} + +GPUShader *OVERLAY_shader_extra(bool is_select) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + GPUShader **sh = (is_select) ? &sh_data->extra_select : &sh_data->extra; + if (!*sh) { + *sh = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? (is_select ? "overlay_extra_select_clipped" : "overlay_extra_clipped") : + (is_select ? "overlay_extra_select" : "overlay_extra")); + } + return *sh; +} + +GPUShader *OVERLAY_shader_extra_grid(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->extra_lightprobe_grid) { + sh_data->extra_lightprobe_grid = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_extra_grid_clipped" : "overlay_extra_grid"); + } + return sh_data->extra_lightprobe_grid; +} + +GPUShader *OVERLAY_shader_extra_groundline(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_extra_groundline_clipped" : "overlay_extra_groundline"); + } + return sh_data->extra_groundline; +} + +GPUShader *OVERLAY_shader_extra_wire(bool use_object, bool is_select) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + GPUShader **sh = (is_select) ? &sh_data->extra_wire_select : &sh_data->extra_wire[use_object]; + if (!*sh) { + const char *info_name = nullptr; + if (draw_ctx->sh_cfg) { + if (is_select) { + info_name = "overlay_extra_wire_select_clipped"; + } + else { + info_name = use_object ? "overlay_extra_wire_object_clipped" : + "overlay_extra_wire_clipped"; + } + } + else { + if (is_select) { + info_name = "overlay_extra_wire_select"; + } + else { + info_name = use_object ? "overlay_extra_wire_object" : "overlay_extra_wire"; + } + } + *sh = GPU_shader_create_from_info_name(info_name); + } + return *sh; +} + +GPUShader *OVERLAY_shader_extra_loose_point(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_extra_loose_point_clipped" : "overlay_extra_loose_point"); + } + return sh_data->extra_loose_point; +} + +GPUShader *OVERLAY_shader_extra_point(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_extra_point_clipped" : "overlay_extra_point"); + } + return sh_data->extra_point; +} + +GPUShader *OVERLAY_shader_facing(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->facing) { + sh_data->facing = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_facing_clipped" : "overlay_facing"); + } + return sh_data->facing; +} + +GPUShader *OVERLAY_shader_gpencil_canvas(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->gpencil_canvas) { + /* TODO(fclem): Support Clipping? Everything is already setup but don't want to change behavior + * without agreement of all gpencil module. */ + sh_data->gpencil_canvas = GPU_shader_create_from_info_name( + 0 ? "overlay_gpencil_canvas_clipped" : "overlay_gpencil_canvas"); + } + return sh_data->gpencil_canvas; +} + +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_info_name("overlay_grid"); + } + return sh_data->grid; +} + +GPUShader *OVERLAY_shader_grid_background(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->grid_background) { + sh_data->grid_background = GPU_shader_create_from_info_name("overlay_grid_background"); + } + return sh_data->grid_background; +} + +GPUShader *OVERLAY_shader_grid_image(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->grid_image) { + sh_data->grid_image = GPU_shader_create_from_info_name("overlay_grid_image"); + } + return sh_data->grid_image; +} + +GPUShader *OVERLAY_shader_edit_uv_stencil_image(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_stencil_image) { + sh_data->edit_uv_stencil_image = GPU_shader_create_from_info_name( + "overlay_edit_uv_stencil_image"); + } + return sh_data->edit_uv_stencil_image; +} + +GPUShader *OVERLAY_shader_edit_uv_mask_image(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_mask_image) { + sh_data->edit_uv_mask_image = GPU_shader_create_from_info_name("overlay_edit_uv_mask_image"); + } + return sh_data->edit_uv_mask_image; +} + +GPUShader *OVERLAY_shader_image(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->image) { + /* TODO(fclem): Do we want to allow clipping reference images? */ + sh_data->image = GPU_shader_create_from_info_name(0 ? "overlay_image_clipped" : + "overlay_image"); + } + return sh_data->image; +} + +GPUShader *OVERLAY_shader_motion_path_line(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_motion_path_line_clipped" : "overlay_motion_path_line"); + } + return sh_data->motion_path_line; +} + +GPUShader *OVERLAY_shader_motion_path_vert(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_motion_path_point_clipped" : "overlay_motion_path_point"); + } + return sh_data->motion_path_vert; +} + +GPUShader *OVERLAY_shader_outline_prepass(bool use_wire) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_outline_prepass_wire_clipped" : + "overlay_outline_prepass_wire"); + } + else if (!sh_data->outline_prepass) { + sh_data->outline_prepass = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_outline_prepass_mesh_clipped" : + "overlay_outline_prepass_mesh"); + } + return use_wire ? sh_data->outline_prepass_wire : sh_data->outline_prepass; +} + +GPUShader *OVERLAY_shader_outline_prepass_curves() +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->outline_prepass_curves) { + sh_data->outline_prepass_curves = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_outline_prepass_curves_clipped" : + "overlay_outline_prepass_curves"); + } + return sh_data->outline_prepass_curves; +} + +GPUShader *OVERLAY_shader_outline_prepass_gpencil(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->outline_prepass_gpencil) { + sh_data->outline_prepass_gpencil = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_outline_prepass_gpencil_clipped" : + "overlay_outline_prepass_gpencil"); + } + return sh_data->outline_prepass_gpencil; +} + +GPUShader *OVERLAY_shader_outline_prepass_pointcloud(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->outline_prepass_pointcloud) { + sh_data->outline_prepass_pointcloud = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_outline_prepass_pointcloud_clipped" : + "overlay_outline_prepass_pointcloud"); + } + return sh_data->outline_prepass_pointcloud; +} + +GPUShader *OVERLAY_shader_outline_detect(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->outline_detect) { + sh_data->outline_detect = GPU_shader_create_from_info_name("overlay_outline_detect"); + } + return sh_data->outline_detect; +} + +GPUShader *OVERLAY_shader_paint_face(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg; + OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_cfg]; + if (!sh_data->paint_face) { + sh_data->paint_face = GPU_shader_create_from_info_name( + sh_cfg == GPU_SHADER_CFG_CLIPPED ? "overlay_paint_face_clipped" : "overlay_paint_face"); + } + return sh_data->paint_face; +} + +GPUShader *OVERLAY_shader_paint_point(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg; + OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_cfg]; + if (!sh_data->paint_point) { + sh_data->paint_point = GPU_shader_create_from_info_name( + sh_cfg == GPU_SHADER_CFG_CLIPPED ? "overlay_paint_point_clipped" : "overlay_paint_point"); + } + return sh_data->paint_point; +} + +GPUShader *OVERLAY_shader_paint_texture(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg; + OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_cfg]; + if (!sh_data->paint_texture) { + sh_data->paint_texture = GPU_shader_create_from_info_name( + sh_cfg ? "overlay_paint_texture_clipped" : "overlay_paint_texture"); + } + return sh_data->paint_texture; +} + +GPUShader *OVERLAY_shader_paint_vertcol(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg; + OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_cfg]; + if (!sh_data->paint_vertcol) { + sh_data->paint_vertcol = GPU_shader_create_from_info_name( + sh_cfg ? "overlay_paint_vertcol_clipped" : "overlay_paint_vertcol"); + } + return sh_data->paint_vertcol; +} + +GPUShader *OVERLAY_shader_paint_weight(const bool shading) +{ + const char *info_name[2][2] = { + {"overlay_paint_weight", "overlay_paint_weight_fake_shading"}, + {"overlay_paint_weight_clipped", "overlay_paint_weight_fake_shading_clipped"}, + }; + int index = shading ? 1 : 0; + const DRWContextState *draw_ctx = DRW_context_state_get(); + eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg; + OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_cfg]; + if (!sh_data->paint_weight[index]) { + sh_data->paint_weight[index] = GPU_shader_create_from_info_name(info_name[sh_cfg][index]); + } + return sh_data->paint_weight[index]; +} + +GPUShader *OVERLAY_shader_paint_wire(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + eGPUShaderConfig sh_cfg = draw_ctx->sh_cfg; + OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_cfg]; + if (!sh_data->paint_wire) { + sh_data->paint_wire = GPU_shader_create_from_info_name(sh_cfg ? "overlay_paint_wire_clipped" : + "overlay_paint_wire"); + } + return sh_data->paint_wire; +} + +GPUShader *OVERLAY_shader_particle_dot(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_particle_dot_clipped" : "overlay_particle_dot"); + } + return sh_data->particle_dot; +} + +GPUShader *OVERLAY_shader_particle_shape(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_particle_shape_clipped" : "overlay_particle_shape"); + } + return sh_data->particle_shape; +} + +GPUShader *OVERLAY_shader_sculpt_mask(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_sculpt_mask_clipped" : "overlay_sculpt_mask"); + } + return sh_data->sculpt_mask; +} + +GPUShader *OVERLAY_shader_sculpt_curves_selection(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->sculpt_curves_selection) { + sh_data->sculpt_curves_selection = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED ? "overlay_sculpt_curves_selection_clipped" : + "overlay_sculpt_curves_selection"); + } + return sh_data->sculpt_curves_selection; +} + +struct GPUShader *OVERLAY_shader_uniform_color(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_uniform_color_clipped" : "overlay_uniform_color"); + } + return sh_data->uniform_color; +} + +struct GPUShader *OVERLAY_shader_volume_velocity(bool use_needle, bool use_mac) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (use_needle && !sh_data->volume_velocity_needle_sh) { + sh_data->volume_velocity_needle_sh = GPU_shader_create_from_info_name( + "overlay_volume_velocity_needle"); + } + else if (use_mac && !sh_data->volume_velocity_mac_sh) { + sh_data->volume_velocity_mac_sh = GPU_shader_create_from_info_name( + "overlay_volume_velocity_mac"); + } + else if (!sh_data->volume_velocity_sh) { + sh_data->volume_velocity_sh = GPU_shader_create_from_info_name("overlay_volume_velocity"); + } + + if (use_needle) { + return sh_data->volume_velocity_needle_sh; + } + if (use_mac) { + return sh_data->volume_velocity_mac_sh; + } + return sh_data->volume_velocity_sh; +} + +struct GPUShader *OVERLAY_shader_volume_gridlines(bool color_with_flags, bool color_range) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->volume_gridlines_flags_sh && color_with_flags) { + sh_data->volume_gridlines_flags_sh = GPU_shader_create_from_info_name( + "overlay_volume_gridlines_flags"); + } + else if (!sh_data->volume_gridlines_range_sh && color_range) { + sh_data->volume_gridlines_range_sh = GPU_shader_create_from_info_name( + "overlay_volume_gridlines_range"); + } + else if (!sh_data->volume_gridlines_sh) { + sh_data->volume_gridlines_sh = GPU_shader_create_from_info_name("overlay_volume_gridlines"); + } + + if (color_with_flags) { + return sh_data->volume_gridlines_flags_sh; + } + if (color_range) { + return sh_data->volume_gridlines_range_sh; + } + + return sh_data->volume_gridlines_sh; +} + +GPUShader *OVERLAY_shader_wireframe_select(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + 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_info_name( + draw_ctx->sh_cfg ? "overlay_wireframe_select_clipped" : "overlay_wireframe_select"); + } + return sh_data->wireframe_select; +} + +GPUShader *OVERLAY_shader_wireframe(bool custom_bias) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->wireframe[custom_bias]) { + sh_data->wireframe[custom_bias] = GPU_shader_create_from_info_name( + custom_bias ? (draw_ctx->sh_cfg ? "overlay_wireframe_custom_depth_clipped" : + "overlay_wireframe_custom_depth") : + (draw_ctx->sh_cfg ? "overlay_wireframe_clipped" : "overlay_wireframe")); + } + return sh_data->wireframe[custom_bias]; +} + +GPUShader *OVERLAY_shader_xray_fade(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->xray_fade) { + sh_data->xray_fade = GPU_shader_create_from_info_name("overlay_xray_fade"); + } + return sh_data->xray_fade; +} + +/* -------------------------------------------------------------------- */ +/** \name Edit UV shaders + * \{ */ + +GPUShader *OVERLAY_shader_edit_uv_edges_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_edges) { + sh_data->edit_uv_edges = GPU_shader_create_from_info_name("overlay_edit_uv_edges"); + } + return sh_data->edit_uv_edges; +} + +GPUShader *OVERLAY_shader_edit_uv_edges_for_edge_select_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_edges_for_edge_select) { + sh_data->edit_uv_edges_for_edge_select = GPU_shader_create_from_info_name( + "overlay_edit_uv_edges_select"); + } + return sh_data->edit_uv_edges_for_edge_select; +} + +GPUShader *OVERLAY_shader_edit_uv_face_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_faces) { + sh_data->edit_uv_faces = GPU_shader_create_from_info_name("overlay_edit_uv_faces"); + } + return sh_data->edit_uv_faces; +} + +GPUShader *OVERLAY_shader_edit_uv_face_dots_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_face_dots) { + sh_data->edit_uv_face_dots = GPU_shader_create_from_info_name("overlay_edit_uv_face_dots"); + } + return sh_data->edit_uv_face_dots; +} + +GPUShader *OVERLAY_shader_edit_uv_verts_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_verts) { + sh_data->edit_uv_verts = GPU_shader_create_from_info_name("overlay_edit_uv_verts"); + } + + return sh_data->edit_uv_verts; +} + +GPUShader *OVERLAY_shader_edit_uv_stretching_area_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_stretching_area) { + sh_data->edit_uv_stretching_area = GPU_shader_create_from_info_name( + "overlay_edit_uv_stretching_area"); + } + + return sh_data->edit_uv_stretching_area; +} + +GPUShader *OVERLAY_shader_edit_uv_stretching_angle_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_stretching_angle) { + sh_data->edit_uv_stretching_angle = GPU_shader_create_from_info_name( + "overlay_edit_uv_stretching_angle"); + } + + return sh_data->edit_uv_stretching_angle; +} + +GPUShader *OVERLAY_shader_edit_uv_tiled_image_borders_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_tiled_image_borders) { + sh_data->edit_uv_tiled_image_borders = GPU_shader_create_from_info_name( + "overlay_edit_uv_tiled_image_borders"); + } + return sh_data->edit_uv_tiled_image_borders; +} + +/** \} */ + +static OVERLAY_InstanceFormats g_formats = {nullptr}; + +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.point_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); + } +} diff --git a/source/blender/draw/engines/overlay/overlay_shader_shared.h b/source/blender/draw/engines/overlay/overlay_shader_shared.h index 339b6f02e1a..739e5be6c2f 100644 --- a/source/blender/draw/engines/overlay/overlay_shader_shared.h +++ b/source/blender/draw/engines/overlay/overlay_shader_shared.h @@ -38,6 +38,9 @@ enum OVERLAY_GridBits { PLANE_IMAGE = (1u << 11u), CUSTOM_GRID = (1u << 12u), }; +#ifndef GPU_SHADER +ENUM_OPERATORS(OVERLAY_GridBits, CUSTOM_GRID) +#endif /* Match: #SI_GRID_STEPS_LEN */ #define OVERLAY_GRID_STEPS_LEN 8 diff --git a/source/blender/draw/engines/overlay/overlay_volume.c b/source/blender/draw/engines/overlay/overlay_volume.c deleted file mode 100644 index ee0d80734ab..00000000000 --- a/source/blender/draw/engines/overlay/overlay_volume.c +++ /dev/null @@ -1,53 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup draw_engine - */ - -#include "DNA_volume_types.h" - -#include "DRW_render.h" -#include "GPU_shader.h" - -#include "overlay_private.h" - -void OVERLAY_volume_cache_init(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_PrivateData *pd = vedata->stl->pd; - const bool is_select = DRW_state_is_select(); - - if (is_select) { - DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - DRW_PASS_CREATE(psl->volume_ps, state | pd->clipping_state); - GPUShader *sh = OVERLAY_shader_depth_only(); - DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->volume_ps); - pd->volume_selection_surface_grp = grp; - } - else { - psl->volume_ps = NULL; - pd->volume_selection_surface_grp = NULL; - } -} - -void OVERLAY_volume_cache_populate(OVERLAY_Data *vedata, Object *ob) -{ - OVERLAY_PrivateData *pd = vedata->stl->pd; - const bool is_select = DRW_state_is_select(); - - if (is_select) { - struct GPUBatch *geom = DRW_cache_volume_selection_surface_get(ob); - if (geom != NULL) { - DRW_shgroup_call(pd->volume_selection_surface_grp, geom, ob); - } - } -} - -void OVERLAY_volume_draw(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - - if (psl->volume_ps) { - DRW_draw_pass(psl->volume_ps); - } -} diff --git a/source/blender/draw/engines/overlay/overlay_volume.cc b/source/blender/draw/engines/overlay/overlay_volume.cc new file mode 100644 index 00000000000..daf76c394b3 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_volume.cc @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup draw_engine + */ + +#include "DNA_volume_types.h" + +#include "DRW_render.h" +#include "GPU_shader.h" + +#include "overlay_private.hh" + +void OVERLAY_volume_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + const bool is_select = DRW_state_is_select(); + + if (is_select) { + DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + DRW_PASS_CREATE(psl->volume_ps, state | pd->clipping_state); + GPUShader *sh = OVERLAY_shader_depth_only(); + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->volume_ps); + pd->volume_selection_surface_grp = grp; + } + else { + psl->volume_ps = nullptr; + pd->volume_selection_surface_grp = nullptr; + } +} + +void OVERLAY_volume_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + const bool is_select = DRW_state_is_select(); + + if (is_select) { + struct GPUBatch *geom = DRW_cache_volume_selection_surface_get(ob); + if (geom != nullptr) { + DRW_shgroup_call(pd->volume_selection_surface_grp, geom, ob); + } + } +} + +void OVERLAY_volume_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + if (psl->volume_ps) { + DRW_draw_pass(psl->volume_ps); + } +} diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c deleted file mode 100644 index a5628559cfd..00000000000 --- a/source/blender/draw/engines/overlay/overlay_wireframe.c +++ /dev/null @@ -1,360 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2019 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - */ - -#include "DNA_collection_types.h" -#include "DNA_mesh_types.h" -#include "DNA_particle_types.h" -#include "DNA_view3d_types.h" -#include "DNA_volume_types.h" - -#include "BKE_curve.h" -#include "BKE_displist.h" -#include "BKE_duplilist.h" -#include "BKE_editmesh.h" -#include "BKE_global.h" -#include "BKE_object.h" -#include "BKE_paint.h" -#include "BKE_particle.h" - -#include "BLI_hash.h" - -#include "DRW_render.h" -#include "GPU_shader.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(); - DRWView *default_view = (DRWView *)DRW_view_default_get(); - pd->view_wires = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 0.5f); -} - -void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) -{ - OVERLAY_PassList *psl = vedata->psl; - OVERLAY_TextureList *txl = vedata->txl; - 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; - pd->shdata.wire_opacity = pd->overlay.wireframe_opacity; - - 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(pd->antialiasing.enabled); - - for (int xray = 0; xray < (is_material_shmode ? 1 : 2); xray++) { - DRWState state = DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR | - DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - DRWPass *pass; - GPUTexture **depth_tx = ((!pd->xray_enabled || pd->xray_opacity > 0.0f) && - DRW_state_is_fbo()) ? - &txl->temp_depth_tx : - &txl->dummy_depth_tx; - - if (xray == 0) { - DRW_PASS_CREATE(psl->wireframe_ps, state | pd->clipping_state); - pass = psl->wireframe_ps; - } - else { - DRW_PASS_CREATE(psl->wireframe_xray_ps, state | pd->clipping_state); - pass = psl->wireframe_xray_ps; - } - - 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(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx); - DRW_shgroup_uniform_float_copy(grp, "wireStepParam", pd->shdata.wire_step_param); - DRW_shgroup_uniform_float_copy(grp, "wireOpacity", pd->shdata.wire_opacity); - 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_uniform_bool_copy(grp, "isHair", false); - - pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass); - DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 1.0f); - - pd->wires_hair_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass); - DRW_shgroup_uniform_bool_copy(grp, "isHair", true); - DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f); - } - - pd->wires_sculpt_grp[xray] = grp = DRW_shgroup_create(wires_sh, pass); - DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx); - DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f); - DRW_shgroup_uniform_bool_copy(grp, "useColoring", false); - DRW_shgroup_uniform_bool_copy(grp, "isHair", false); - } - - if (is_material_shmode) { - /* Make all drawcalls go into the non-xray shading groups. */ - for (int use_coloring = 0; use_coloring < 2; use_coloring++) { - pd->wires_grp[1][use_coloring] = pd->wires_grp[0][use_coloring]; - pd->wires_all_grp[1][use_coloring] = pd->wires_all_grp[0][use_coloring]; - pd->wires_hair_grp[1][use_coloring] = pd->wires_hair_grp[0][use_coloring]; - } - pd->wires_sculpt_grp[1] = pd->wires_sculpt_grp[0]; - psl->wireframe_xray_ps = NULL; - } -} - -static void wireframe_hair_cache_populate(OVERLAY_Data *vedata, Object *ob, ParticleSystem *psys) -{ - OVERLAY_PrivateData *pd = vedata->stl->pd; - const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; - - Object *dupli_parent = DRW_object_get_dupli_parent(ob); - DupliObject *dupli_object = DRW_object_get_dupli(ob); - - float dupli_mat[4][4]; - if ((dupli_parent != NULL) && (dupli_object != NULL)) { - if (dupli_object->type & OB_DUPLICOLLECTION) { - unit_m4(dupli_mat); - Collection *collection = dupli_parent->instance_collection; - if (collection != NULL) { - sub_v3_v3(dupli_mat[3], collection->instance_offset); - } - mul_m4_m4m4(dupli_mat, dupli_parent->obmat, dupli_mat); - } - else { - copy_m4_m4(dupli_mat, dupli_object->ob->obmat); - invert_m4(dupli_mat); - mul_m4_m4m4(dupli_mat, ob->obmat, dupli_mat); - } - } - else { - unit_m4(dupli_mat); - } - - struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL); - - const bool use_coloring = true; - DRWShadingGroup *shgrp = DRW_shgroup_create_sub(pd->wires_hair_grp[is_xray][use_coloring]); - DRW_shgroup_uniform_mat4_copy(shgrp, "hairDupliMatrix", dupli_mat); - DRW_shgroup_call_no_cull(shgrp, hairs, ob); -} - -void OVERLAY_wireframe_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(); - const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES) != 0; - const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; - const bool is_mesh = ob->type == OB_MESH; - const bool is_edit_mode = DRW_object_is_in_edit_mode(ob); - bool has_edit_mesh_cage = false; - bool is_mesh_verts_only = false; - if (is_mesh) { - /* TODO: Should be its own function. */ - Mesh *me = ob->data; - if (is_edit_mode) { - BLI_assert(me->edit_mesh); - Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob); - Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob); - has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_eval_final); - if (editmesh_eval_final) { - me = editmesh_eval_final; - } - } - is_mesh_verts_only = me->totedge == 0 && me->totvert > 0; - } - - const bool use_wire = !is_mesh_verts_only && ((pd->overlay.flag & V3D_OVERLAY_WIREFRAMES) || - (ob->dtx & OB_DRAWWIRE) || (ob->dt == OB_WIRE)); - - if (use_wire && pd->wireframe_mode && ob->particlesystem.first) { - for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) { - if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) { - continue; - } - ParticleSettings *part = psys->part; - const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - if (draw_as == PART_DRAW_PATH) { - wireframe_hair_cache_populate(vedata, ob, psys); - } - } - } - - if (ELEM(ob->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) { - OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob); - float *color; - DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); - - struct GPUBatch *geom = NULL; - switch (ob->type) { - case OB_CURVES_LEGACY: - geom = DRW_cache_curve_edge_wire_get(ob); - break; - case OB_FONT: - geom = DRW_cache_text_edge_wire_get(ob); - break; - case OB_SURF: - geom = DRW_cache_surf_edge_wire_get(ob); - break; - } - - if (geom) { - OVERLAY_extra_wire(cb, geom, ob->obmat, color); - } - } - - /* Fast path for duplis. */ - if (dupli && !init_dupli) { - if (dupli->wire_shgrp && dupli->wire_geom) { - if (dupli->base_flag == ob->base_flag) { - /* Check for the special cases used below, assign specific theme colors to the shaders. */ - OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob); - if (dupli->wire_shgrp == cb->extra_loose_points) { - float *color; - DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); - OVERLAY_extra_loose_points(cb, dupli->wire_geom, ob->obmat, color); - } - else if (dupli->wire_shgrp == cb->extra_wire) { - float *color; - DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); - OVERLAY_extra_wire(cb, dupli->wire_geom, ob->obmat, color); - } - else { - DRW_shgroup_call(dupli->wire_shgrp, dupli->wire_geom, ob); - } - return; - } - } - else { - /* Nothing to draw for this dupli. */ - return; - } - } - - if (use_wire && ELEM(ob->type, OB_VOLUME, OB_POINTCLOUD)) { - bool draw_as_points = true; - if (ob->type == OB_VOLUME) { - /* Volume object as points exception. */ - Volume *volume = ob->data; - draw_as_points = volume->display.wireframe_type == VOLUME_WIREFRAME_POINTS; - } - - if (draw_as_points) { - float *color; - OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob); - DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); - - struct GPUBatch *geom = DRW_cache_object_face_wireframe_get(ob); - if (geom) { - OVERLAY_extra_loose_points(cb, geom, ob->obmat, color); - } - return; - } - } - - DRWShadingGroup *shgrp = NULL; - struct GPUBatch *geom = NULL; - - /* 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 is_sculpt_mode = ((ob->mode & OB_MODE_SCULPT) != 0) && (ob->sculpt != NULL); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - const bool is_instance = (ob->base_flag & BASE_FROM_DUPLI); - const bool instance_parent_in_edit_mode = is_instance ? DRW_object_is_in_edit_mode( - DRW_object_get_dupli_parent(ob)) : - false; - const bool use_coloring = (use_wire && !is_edit_mode && !is_sculpt_mode && - !has_edit_mesh_cage && !instance_parent_in_edit_mode); - 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 (ob->type == OB_GPENCIL) { - /* TODO(fclem): Make GPencil objects have correct bound-box. */ - DRW_shgroup_call_no_cull(shgrp, geom, ob); - } - else if (use_sculpt_pbvh) { - DRW_shgroup_call_sculpt(shgrp, ob, true, false); - } - else { - DRW_shgroup_call(shgrp, geom, ob); - } - } - } - else if (is_mesh && (!is_edit_mode || has_edit_mesh_cage)) { - OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob); - float *color; - DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); - - /* Draw loose geometry. */ - if (is_mesh_verts_only) { - geom = DRW_cache_mesh_all_verts_get(ob); - if (geom) { - OVERLAY_extra_loose_points(cb, geom, ob->obmat, color); - shgrp = cb->extra_loose_points; - } - } - else { - geom = DRW_cache_mesh_loose_edges_get(ob); - if (geom) { - OVERLAY_extra_wire(cb, geom, ob->obmat, color); - shgrp = cb->extra_wire; - } - } - } - - if (dupli) { - dupli->wire_shgrp = shgrp; - dupli->wire_geom = geom; - } -} - -void OVERLAY_wireframe_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_ps); - - DRW_view_set_active(NULL); -} - -void OVERLAY_wireframe_in_front_draw(OVERLAY_Data *data) -{ - OVERLAY_PassList *psl = data->psl; - OVERLAY_PrivateData *pd = data->stl->pd; - - if (psl->wireframe_xray_ps) { - DRW_view_set_active(pd->view_wires); - DRW_draw_pass(psl->wireframe_xray_ps); - - DRW_view_set_active(NULL); - } -} diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.cc b/source/blender/draw/engines/overlay/overlay_wireframe.cc new file mode 100644 index 00000000000..edaa96651b2 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_wireframe.cc @@ -0,0 +1,362 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2019 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + */ + +#include "DNA_collection_types.h" +#include "DNA_mesh_types.h" +#include "DNA_particle_types.h" +#include "DNA_view3d_types.h" +#include "DNA_volume_types.h" + +#include "BKE_curve.h" +#include "BKE_displist.h" +#include "BKE_duplilist.h" +#include "BKE_editmesh.h" +#include "BKE_global.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_particle.h" + +#include "BLI_hash.h" + +#include "DRW_render.h" +#include "GPU_shader.h" + +#include "ED_view3d.h" + +#include "overlay_private.hh" + +void OVERLAY_wireframe_init(OVERLAY_Data *vedata) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + const DRWContextState *draw_ctx = DRW_context_state_get(); + DRWView *default_view = (DRWView *)DRW_view_default_get(); + pd->view_wires = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 0.5f); +} + +void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_TextureList *txl = vedata->txl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + const DRWContextState *draw_ctx = DRW_context_state_get(); + DRWShadingGroup *grp = nullptr; + + View3DShading *shading = &draw_ctx->v3d->shading; + + pd->shdata.wire_step_param = pd->overlay.wireframe_threshold - 254.0f / 255.0f; + pd->shdata.wire_opacity = pd->overlay.wireframe_opacity; + + 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(pd->antialiasing.enabled); + + for (int xray = 0; xray < (is_material_shmode ? 1 : 2); xray++) { + DRWState state = DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR | + DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + DRWPass *pass; + GPUTexture **depth_tx = ((!pd->xray_enabled || pd->xray_opacity > 0.0f) && + DRW_state_is_fbo()) ? + &txl->temp_depth_tx : + &txl->dummy_depth_tx; + + if (xray == 0) { + DRW_PASS_CREATE(psl->wireframe_ps, state | pd->clipping_state); + pass = psl->wireframe_ps; + } + else { + DRW_PASS_CREATE(psl->wireframe_xray_ps, state | pd->clipping_state); + pass = psl->wireframe_xray_ps; + } + + 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(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx); + DRW_shgroup_uniform_float_copy(grp, "wireStepParam", pd->shdata.wire_step_param); + DRW_shgroup_uniform_float_copy(grp, "wireOpacity", pd->shdata.wire_opacity); + 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_uniform_bool_copy(grp, "isHair", false); + + pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass); + DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 1.0f); + + pd->wires_hair_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass); + DRW_shgroup_uniform_bool_copy(grp, "isHair", true); + DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f); + } + + pd->wires_sculpt_grp[xray] = grp = DRW_shgroup_create(wires_sh, pass); + DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx); + DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f); + DRW_shgroup_uniform_bool_copy(grp, "useColoring", false); + DRW_shgroup_uniform_bool_copy(grp, "isHair", false); + } + + if (is_material_shmode) { + /* Make all drawcalls go into the non-xray shading groups. */ + for (int use_coloring = 0; use_coloring < 2; use_coloring++) { + pd->wires_grp[1][use_coloring] = pd->wires_grp[0][use_coloring]; + pd->wires_all_grp[1][use_coloring] = pd->wires_all_grp[0][use_coloring]; + pd->wires_hair_grp[1][use_coloring] = pd->wires_hair_grp[0][use_coloring]; + } + pd->wires_sculpt_grp[1] = pd->wires_sculpt_grp[0]; + psl->wireframe_xray_ps = nullptr; + } +} + +static void wireframe_hair_cache_populate(OVERLAY_Data *vedata, Object *ob, ParticleSystem *psys) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; + + Object *dupli_parent = DRW_object_get_dupli_parent(ob); + DupliObject *dupli_object = DRW_object_get_dupli(ob); + + float dupli_mat[4][4]; + if ((dupli_parent != nullptr) && (dupli_object != nullptr)) { + if (dupli_object->type & OB_DUPLICOLLECTION) { + unit_m4(dupli_mat); + Collection *collection = dupli_parent->instance_collection; + if (collection != nullptr) { + sub_v3_v3(dupli_mat[3], collection->instance_offset); + } + mul_m4_m4m4(dupli_mat, dupli_parent->obmat, dupli_mat); + } + else { + copy_m4_m4(dupli_mat, dupli_object->ob->obmat); + invert_m4(dupli_mat); + mul_m4_m4m4(dupli_mat, ob->obmat, dupli_mat); + } + } + else { + unit_m4(dupli_mat); + } + + struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, nullptr); + + const bool use_coloring = true; + DRWShadingGroup *shgrp = DRW_shgroup_create_sub(pd->wires_hair_grp[is_xray][use_coloring]); + DRW_shgroup_uniform_mat4_copy(shgrp, "hairDupliMatrix", dupli_mat); + DRW_shgroup_call_no_cull(shgrp, hairs, ob); +} + +void OVERLAY_wireframe_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(); + const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES) != 0; + const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; + const bool is_mesh = ob->type == OB_MESH; + const bool is_edit_mode = DRW_object_is_in_edit_mode(ob); + bool has_edit_mesh_cage = false; + bool is_mesh_verts_only = false; + if (is_mesh) { + /* TODO: Should be its own function. */ + Mesh *me = static_cast(ob->data); + if (is_edit_mode) { + BLI_assert(me->edit_mesh); + Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob); + Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob); + has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_eval_final); + if (editmesh_eval_final) { + me = editmesh_eval_final; + } + } + is_mesh_verts_only = me->totedge == 0 && me->totvert > 0; + } + + const bool use_wire = !is_mesh_verts_only && ((pd->overlay.flag & V3D_OVERLAY_WIREFRAMES) || + (ob->dtx & OB_DRAWWIRE) || (ob->dt == OB_WIRE)); + + if (use_wire && pd->wireframe_mode && ob->particlesystem.first) { + for (ParticleSystem *psys = static_cast(ob->particlesystem.first); + psys != nullptr; + psys = psys->next) { + if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) { + continue; + } + ParticleSettings *part = psys->part; + const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; + if (draw_as == PART_DRAW_PATH) { + wireframe_hair_cache_populate(vedata, ob, psys); + } + } + } + + if (ELEM(ob->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) { + OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob); + float *color; + DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); + + struct GPUBatch *geom = nullptr; + switch (ob->type) { + case OB_CURVES_LEGACY: + geom = DRW_cache_curve_edge_wire_get(ob); + break; + case OB_FONT: + geom = DRW_cache_text_edge_wire_get(ob); + break; + case OB_SURF: + geom = DRW_cache_surf_edge_wire_get(ob); + break; + } + + if (geom) { + OVERLAY_extra_wire(cb, geom, ob->obmat, color); + } + } + + /* Fast path for duplis. */ + if (dupli && !init_dupli) { + if (dupli->wire_shgrp && dupli->wire_geom) { + if (dupli->base_flag == ob->base_flag) { + /* Check for the special cases used below, assign specific theme colors to the shaders. */ + OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob); + if (dupli->wire_shgrp == cb->extra_loose_points) { + float *color; + DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); + OVERLAY_extra_loose_points(cb, dupli->wire_geom, ob->obmat, color); + } + else if (dupli->wire_shgrp == cb->extra_wire) { + float *color; + DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); + OVERLAY_extra_wire(cb, dupli->wire_geom, ob->obmat, color); + } + else { + DRW_shgroup_call(dupli->wire_shgrp, dupli->wire_geom, ob); + } + return; + } + } + else { + /* Nothing to draw for this dupli. */ + return; + } + } + + if (use_wire && ELEM(ob->type, OB_VOLUME, OB_POINTCLOUD)) { + bool draw_as_points = true; + if (ob->type == OB_VOLUME) { + /* Volume object as points exception. */ + Volume *volume = static_cast(ob->data); + draw_as_points = volume->display.wireframe_type == VOLUME_WIREFRAME_POINTS; + } + + if (draw_as_points) { + float *color; + OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob); + DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); + + struct GPUBatch *geom = DRW_cache_object_face_wireframe_get(ob); + if (geom) { + OVERLAY_extra_loose_points(cb, geom, ob->obmat, color); + } + return; + } + } + + DRWShadingGroup *shgrp = nullptr; + struct GPUBatch *geom = nullptr; + + /* 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 is_sculpt_mode = ((ob->mode & OB_MODE_SCULPT) != 0) && (ob->sculpt != nullptr); + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + !DRW_state_is_image_render(); + const bool is_instance = (ob->base_flag & BASE_FROM_DUPLI); + const bool instance_parent_in_edit_mode = is_instance ? DRW_object_is_in_edit_mode( + DRW_object_get_dupli_parent(ob)) : + false; + const bool use_coloring = (use_wire && !is_edit_mode && !is_sculpt_mode && + !has_edit_mesh_cage && !instance_parent_in_edit_mode); + 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 (ob->type == OB_GPENCIL) { + /* TODO(fclem): Make GPencil objects have correct bound-box. */ + DRW_shgroup_call_no_cull(shgrp, geom, ob); + } + else if (use_sculpt_pbvh) { + DRW_shgroup_call_sculpt(shgrp, ob, true, false); + } + else { + DRW_shgroup_call(shgrp, geom, ob); + } + } + } + else if (is_mesh && (!is_edit_mode || has_edit_mesh_cage)) { + OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob); + float *color; + DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color); + + /* Draw loose geometry. */ + if (is_mesh_verts_only) { + geom = DRW_cache_mesh_all_verts_get(ob); + if (geom) { + OVERLAY_extra_loose_points(cb, geom, ob->obmat, color); + shgrp = cb->extra_loose_points; + } + } + else { + geom = DRW_cache_mesh_loose_edges_get(ob); + if (geom) { + OVERLAY_extra_wire(cb, geom, ob->obmat, color); + shgrp = cb->extra_wire; + } + } + } + + if (dupli) { + dupli->wire_shgrp = shgrp; + dupli->wire_geom = geom; + } +} + +void OVERLAY_wireframe_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_ps); + + DRW_view_set_active(nullptr); +} + +void OVERLAY_wireframe_in_front_draw(OVERLAY_Data *data) +{ + OVERLAY_PassList *psl = data->psl; + OVERLAY_PrivateData *pd = data->stl->pd; + + if (psl->wireframe_xray_ps) { + DRW_view_set_active(pd->view_wires); + DRW_draw_pass(psl->wireframe_xray_ps); + + DRW_view_set_active(nullptr); + } +} diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc index e7baac63aae..dc631483857 100644 --- a/source/blender/draw/tests/shaders_test.cc +++ b/source/blender/draw/tests/shaders_test.cc @@ -17,7 +17,7 @@ #include "engines/eevee/eevee_private.h" #include "engines/gpencil/gpencil_engine.h" #include "engines/image/image_private.hh" -#include "engines/overlay/overlay_private.h" +#include "engines/overlay/overlay_private.hh" #include "engines/workbench/workbench_private.h" #include "intern/draw_shader.h" -- cgit v1.2.3