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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2022-09-19 15:29:58 +0300
committerJacques Lucke <jacques@blender.org>2022-09-19 15:29:58 +0300
commit2fffd7d7a85d9e35d4f2b6e0de15504178b26e07 (patch)
tree0b71bd34d0246f0637da738612abe2001962c927 /source/blender/draw/engines/overlay/overlay_extra.cc
parent327802b86f6b4dd0614d67796cc8ef02f4363a9b (diff)
Move overlay engine to C++
This just makes the minimum changes to make the files compile.
Diffstat (limited to 'source/blender/draw/engines/overlay/overlay_extra.cc')
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.cc1623
1 files changed, 1623 insertions, 0 deletions
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<ID *>(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<Curve *>(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<Light *>(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<Camera *>(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<Camera *>(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<Camera *>(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<ModifierData *>(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<bConstraint *>(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<bConstraintTarget *>(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);
+}