Files
test/source/blender/draw/engines/select/select_draw_utils.cc
Hans Goudey d95b1f120b Mesh: Store BMEditMesh in shared pointer
The main motivation for this is that it's part of a fix for #113377,
where I want to propagate the edit mesh pointers through copied
meshes in modifiers and geometry nodes, instead of just setting the
edit mesh pointer at the end of the modifier stack. That would have
two main benefits:
1. We avoid the need to write to the evaluated mesh, after evaluation
  which means it can be shared directly among evaluated objects.
2. When an object's mesh is completely replaced by the mesh from another
   object during evaluation (with the object info node), the final edit
   mesh pointer will not be "wrong", allowing us to skip index-mapped
   GPU data extraction.

Beyond that, using a shared pointer just makes things more automatic.
Handling of edit mesh data is already complicated enough, this way some
of the worry and complexity can be handled by RAII.

One thing to keep in mind is that the edit mesh's BMesh is still freed
manually with `EDBM_mesh_free_data` when leaving edit mode. I figured
that was a more conservative approach for now. Maybe eventually that
could be handled automatically with RAII too.

Pull Request: https://projects.blender.org/blender/blender/pulls/120276
2024-04-18 13:52:20 +02:00

226 lines
7.9 KiB
C++

/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup draw_engine
*
* Engine for drawing a selection map where the pixels indicate the selection indices.
*/
#include "BKE_editmesh.hh"
#include "BKE_mesh.hh"
#include "BKE_object.hh"
#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "ED_view3d.hh"
#include "DEG_depsgraph.hh"
#include "DEG_depsgraph_query.hh"
#include "DRW_select_buffer.hh"
#include "draw_cache_impl.hh"
#include "select_private.hh"
/* -------------------------------------------------------------------- */
/** \name Draw Utilities
* \{ */
short select_id_get_object_select_mode(Scene *scene, Object *ob)
{
short r_select_mode = 0;
if (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) {
/* In order to sample flat colors for vertex weights / texture-paint / vertex-paint
* we need to be in SCE_SELECT_FACE mode so select_cache_init() correctly sets up
* a shgroup with select_id_flat.
* Note this is not working correctly for vertex-paint (yet), but has been discussed
* in #66645 and there is a solution by @mano-wii in P1032.
* So OB_MODE_VERTEX_PAINT is already included here [required for P1032 I guess]. */
Mesh *me_orig = static_cast<Mesh *>(DEG_get_original_object(ob)->data);
if (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) {
r_select_mode = SCE_SELECT_VERTEX;
}
else {
r_select_mode = SCE_SELECT_FACE;
}
}
else {
r_select_mode = scene->toolsettings->selectmode;
}
return r_select_mode;
}
static bool check_ob_drawface_dot(short select_mode, const View3D *v3d, eDrawType dt)
{
if (select_mode & SCE_SELECT_FACE) {
if ((dt < OB_SOLID) || XRAY_FLAG_ENABLED(v3d)) {
return true;
}
if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) {
return true;
}
}
return false;
}
static void draw_select_id_edit_mesh(SELECTID_StorageList *stl,
Object *ob,
short select_mode,
bool draw_facedot,
uint initial_offset,
uint *r_vert_offset,
uint *r_edge_offset,
uint *r_face_offset)
{
using namespace blender::draw;
Mesh *mesh = static_cast<Mesh *>(ob->data);
BMEditMesh *em = mesh->runtime->edit_mesh.get();
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE);
if (select_mode & SCE_SELECT_FACE) {
blender::gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
DRWShadingGroup *face_shgrp = DRW_shgroup_create_sub(stl->g_data->shgrp_face_flat);
DRW_shgroup_uniform_int_copy(face_shgrp, "offset", *(int *)&initial_offset);
DRW_shgroup_call_no_cull(face_shgrp, geom_faces, ob);
if (draw_facedot) {
blender::gpu::Batch *geom_facedots = DRW_mesh_batch_cache_get_facedots_with_select_id(mesh);
DRW_shgroup_call_no_cull(face_shgrp, geom_facedots, ob);
}
*r_face_offset = initial_offset + em->bm->totface;
}
else {
if (ob->dt >= OB_SOLID) {
#ifdef USE_CAGE_OCCLUSION
blender::gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
#else
struct blender::gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface(mesh);
#endif
DRWShadingGroup *face_shgrp = stl->g_data->shgrp_face_unif;
DRW_shgroup_call_no_cull(face_shgrp, geom_faces, ob);
}
*r_face_offset = initial_offset;
}
/* Unlike faces, only draw edges if edge select mode. */
if (select_mode & SCE_SELECT_EDGE) {
blender::gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh);
DRWShadingGroup *edge_shgrp = DRW_shgroup_create_sub(stl->g_data->shgrp_edge);
DRW_shgroup_uniform_int_copy(edge_shgrp, "offset", *(int *)r_face_offset);
DRW_shgroup_call_no_cull(edge_shgrp, geom_edges, ob);
*r_edge_offset = *r_face_offset + em->bm->totedge;
}
else {
/* Note that `r_vert_offset` is calculated from `r_edge_offset`.
* Otherwise the first vertex is never selected, see: #53512. */
*r_edge_offset = *r_face_offset;
}
/* Unlike faces, only verts if vert select mode. */
if (select_mode & SCE_SELECT_VERTEX) {
blender::gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh);
DRWShadingGroup *vert_shgrp = DRW_shgroup_create_sub(stl->g_data->shgrp_vert);
DRW_shgroup_uniform_int_copy(vert_shgrp, "offset", *(int *)r_edge_offset);
DRW_shgroup_call_no_cull(vert_shgrp, geom_verts, ob);
*r_vert_offset = *r_edge_offset + em->bm->totvert;
}
else {
*r_vert_offset = *r_edge_offset;
}
}
static void draw_select_id_mesh(SELECTID_StorageList *stl,
Object *ob,
short select_mode,
uint initial_offset,
uint *r_vert_offset,
uint *r_edge_offset,
uint *r_face_offset)
{
using namespace blender::draw;
Mesh *mesh = static_cast<Mesh *>(ob->data);
blender::gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
DRWShadingGroup *face_shgrp;
if (select_mode & SCE_SELECT_FACE) {
face_shgrp = DRW_shgroup_create_sub(stl->g_data->shgrp_face_flat);
DRW_shgroup_uniform_int_copy(face_shgrp, "offset", *(int *)&initial_offset);
*r_face_offset = initial_offset + mesh->faces_num;
}
else {
/* Only draw faces to mask out verts, we don't want their selection ID's. */
face_shgrp = stl->g_data->shgrp_face_unif;
*r_face_offset = initial_offset;
}
DRW_shgroup_call_no_cull(face_shgrp, geom_faces, ob);
if (select_mode & SCE_SELECT_EDGE) {
blender::gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh);
DRWShadingGroup *edge_shgrp = DRW_shgroup_create_sub(stl->g_data->shgrp_edge);
DRW_shgroup_uniform_int_copy(edge_shgrp, "offset", *(int *)r_face_offset);
DRW_shgroup_call_no_cull(edge_shgrp, geom_edges, ob);
*r_edge_offset = *r_face_offset + mesh->edges_num;
}
else {
*r_edge_offset = *r_face_offset;
}
if (select_mode & SCE_SELECT_VERTEX) {
blender::gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh);
DRWShadingGroup *vert_shgrp = DRW_shgroup_create_sub(stl->g_data->shgrp_vert);
DRW_shgroup_uniform_int_copy(vert_shgrp, "offset", *r_edge_offset);
DRW_shgroup_call_no_cull(vert_shgrp, geom_verts, ob);
*r_vert_offset = *r_edge_offset + mesh->verts_num;
}
else {
*r_vert_offset = *r_edge_offset;
}
}
void select_id_draw_object(void *vedata,
View3D *v3d,
Object *ob,
short select_mode,
uint initial_offset,
uint *r_vert_offset,
uint *r_edge_offset,
uint *r_face_offset)
{
SELECTID_StorageList *stl = ((SELECTID_Data *)vedata)->stl;
BLI_assert(initial_offset > 0);
switch (ob->type) {
case OB_MESH:
if (ob->mode & OB_MODE_EDIT) {
bool draw_facedot = check_ob_drawface_dot(select_mode, v3d, eDrawType(ob->dt));
draw_select_id_edit_mesh(stl,
ob,
select_mode,
draw_facedot,
initial_offset,
r_vert_offset,
r_edge_offset,
r_face_offset);
}
else {
draw_select_id_mesh(
stl, ob, select_mode, initial_offset, r_vert_offset, r_edge_offset, r_face_offset);
}
break;
case OB_CURVES_LEGACY:
case OB_SURF:
break;
}
}
/** \} */
#undef SELECT_ENGINE