Refactor: Select: Use IndexRange for the element selection

This cleanup naming convention and code clarity. There
is no functional change.

- `elem_ranges` is changed to a `Map` to avoid relying on
`sel_data->drawn_index`.
- `select_draw_utils.cc` is merged with `select_engine.cc`
- `index_drawn_len` is renamed to `max_index_drawn_len`
- Remove the usage of `DrawData`

Rel #134690

Pull Request: https://projects.blender.org/blender/blender/pulls/134940
This commit is contained in:
Clément Foucault
2025-02-25 14:40:04 +01:00
committed by Clément Foucault
parent c03ee7f6a8
commit 1b902e305c
8 changed files with 275 additions and 389 deletions

View File

@@ -142,7 +142,6 @@ set(SRC
engines/gpencil/gpencil_render.cc
engines/gpencil/gpencil_shader_c.cc
engines/gpencil/gpencil_shader_fx.cc
engines/select/select_draw_utils.cc
engines/select/select_engine.cc
engines/select/select_instance.cc
engines/overlay/overlay_armature.cc

View File

@@ -8,6 +8,8 @@
#pragma once
#include "BLI_map.hh"
#include "BLI_set.hh"
#include "DNA_ID.h"
#include "BLI_array.hh"
@@ -23,42 +25,27 @@ struct RegionView3D;
struct View3D;
struct rcti;
struct SELECTID_ObjectData {
DrawData dd;
uint drawn_index;
/* Used to avoid adding to the pass more than once. */
bool in_pass;
/* Used to detect and remove objects that are not included in the array. */
bool is_drawn;
};
struct ObjectOffsets {
/* For convenience only. */
union {
uint offset;
uint face_start;
};
union {
uint face;
uint edge_start;
};
union {
uint edge;
uint vert_start;
};
uint vert;
/* Indices inside the selection framebuffer associated with the elements of a mesh. */
struct ElemIndexRanges {
/* Range for each element type. */
blender::IndexRange face;
blender::IndexRange edge;
blender::IndexRange vert;
/* Combined range for the whole object. */
blender::IndexRange total;
};
struct SELECTID_Context {
/* All context objects */
blender::Array<Object *> objects;
blender::Array<ObjectOffsets> index_offsets;
/* All selectable evaluated objects. */
blender::Vector<Object *> objects;
/* Map of the selectable objects from `objects` to their indices ranges. */
blender::Map<Object *, ElemIndexRanges> elem_ranges;
/** Total number of element indices `index_offsets[object_drawn_len - 1].vert`. */
uint index_drawn_len;
/**
* Maximum index value that can be contained inside the selection framebuffer.
* Each object/element type has different range which are described inside `elem_ranges`.
*/
uint max_index_drawn_len;
short select_mode;
@@ -71,7 +58,12 @@ struct SELECTID_Context {
/* `draw_select_buffer.cc` */
bool DRW_select_buffer_elem_get(uint sel_id, uint *r_elem, uint *r_base_index, char *r_elem_type);
bool DRW_select_buffer_elem_get(uint sel_id, uint &r_elem, uint &r_base_index, char &r_elem_type);
/**
* Assume it is called right after `DRW_select_buffer_bitmap_from_*` so that the same evaluated
* object is used for drawing and as parameter to this function.
*/
uint DRW_select_buffer_context_offset_for_object_elem(Depsgraph *depsgraph,
Object *object,
char elem_type);

View File

@@ -1,226 +0,0 @@
/* 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 "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "ED_view3d.hh"
#include "DEG_depsgraph_query.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_Instance &inst,
Object *ob,
ResourceHandle res_handle,
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;
using namespace blender;
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) {
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
PassSimple::Sub *face_sub = inst.select_face_flat;
face_sub->push_constant("offset", int(initial_offset));
face_sub->draw(geom_faces, res_handle);
if (draw_facedot) {
gpu::Batch *geom_facedots = DRW_mesh_batch_cache_get_facedots_with_select_id(mesh);
face_sub->draw(geom_facedots, res_handle);
}
*r_face_offset = initial_offset + em->bm->totface;
}
else {
if (ob->dt >= OB_SOLID) {
#ifdef USE_CAGE_OCCLUSION
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
#else
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface(mesh);
#endif
inst.select_face_uniform->draw(geom_faces, res_handle);
}
*r_face_offset = initial_offset;
}
/* Unlike faces, only draw edges if edge select mode. */
if (select_mode & SCE_SELECT_EDGE) {
gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh);
inst.select_edge->push_constant("offset", int(*r_face_offset));
inst.select_edge->draw(geom_edges, res_handle);
*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) {
gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh);
inst.select_vert->push_constant("offset", int(*r_edge_offset));
inst.select_vert->draw(geom_verts, res_handle);
*r_vert_offset = *r_edge_offset + em->bm->totvert;
}
else {
*r_vert_offset = *r_edge_offset;
}
}
static void draw_select_id_mesh(SELECTID_Instance &inst,
Object *ob,
ResourceHandle res_handle,
short select_mode,
uint initial_offset,
uint *r_vert_offset,
uint *r_edge_offset,
uint *r_face_offset)
{
using namespace blender::draw;
using namespace blender;
Mesh &mesh = *static_cast<Mesh *>(ob->data);
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
if (select_mode & SCE_SELECT_FACE) {
inst.select_face_flat->push_constant("offset", int(initial_offset));
inst.select_face_flat->draw(geom_faces, res_handle);
*r_face_offset = initial_offset + mesh.faces_num;
}
else {
/* Only draw faces to mask out verts, we don't want their selection ID's. */
inst.select_face_uniform->draw(geom_faces, res_handle);
*r_face_offset = initial_offset;
}
if (select_mode & SCE_SELECT_EDGE) {
gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh);
inst.select_edge->push_constant("offset", int(*r_face_offset));
inst.select_edge->draw(geom_edges, res_handle);
*r_edge_offset = *r_face_offset + mesh.edges_num;
}
else {
*r_edge_offset = *r_face_offset;
}
if (select_mode & SCE_SELECT_VERTEX) {
gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh);
inst.select_vert->push_constant("offset", int(*r_edge_offset));
inst.select_vert->draw(geom_verts, res_handle);
*r_vert_offset = *r_edge_offset + mesh.verts_num;
}
else {
*r_vert_offset = *r_edge_offset;
}
}
void select_id_draw_object(SELECTID_Instance &inst,
View3D *v3d,
Object *ob,
ResourceHandle res_handle,
short select_mode,
uint initial_offset,
uint *r_vert_offset,
uint *r_edge_offset,
uint *r_face_offset)
{
BLI_assert(initial_offset > 0);
switch (ob->type) {
case OB_MESH: {
const Mesh &mesh = *static_cast<const Mesh *>(ob->data);
if (mesh.runtime->edit_mesh) {
bool draw_facedot = check_ob_drawface_dot(select_mode, v3d, eDrawType(ob->dt));
draw_select_id_edit_mesh(inst,
ob,
res_handle,
select_mode,
draw_facedot,
initial_offset,
r_vert_offset,
r_edge_offset,
r_face_offset);
}
else {
draw_select_id_mesh(inst,
ob,
res_handle,
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

View File

@@ -8,10 +8,13 @@
* Engine for drawing a selection map where the pixels indicate the selection indices.
*/
#include "BKE_editmesh.hh"
#include "BKE_mesh_types.hh"
#include "BLI_math_matrix.h"
#include "BLT_translation.hh"
#include "DEG_depsgraph_query.hh"
#include "ED_view3d.hh"
#include "RE_engine.h"
@@ -113,6 +116,31 @@ static void select_engine_init(void *vedata)
}
}
static 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 void select_cache_init(void *vedata)
{
SELECTID_Instance &inst = *reinterpret_cast<SELECTID_Data *>(vedata)->instance;
@@ -199,67 +227,200 @@ static void select_cache_init(void *vedata)
}
}
/* Create selection data. */
for (uint sel_id : e_data.context.objects.index_range()) {
Object *obj_eval = e_data.context.objects[sel_id];
DrawData *data = DRW_drawdata_ensure(
&obj_eval->id, &draw_engine_select_type, sizeof(SELECTID_ObjectData), nullptr, nullptr);
SELECTID_ObjectData *sel_data = reinterpret_cast<SELECTID_ObjectData *>(data);
sel_data->drawn_index = sel_id;
sel_data->in_pass = false;
sel_data->is_drawn = false;
}
e_data.context.elem_ranges.clear();
e_data.context.persmat = float4x4(draw_ctx->rv3d->persmat);
e_data.context.index_drawn_len = 1;
e_data.context.max_index_drawn_len = 1;
select_engine_framebuffer_setup();
GPU_framebuffer_bind(e_data.framebuffer_select_id);
GPU_framebuffer_clear_color_depth(e_data.framebuffer_select_id, blender::float4{0.0f}, 1.0f);
}
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;
}
namespace blender {
/* Return a new range if size `n` after `total_range` and grow `total_range` by the same amount. */
static IndexRange alloc_range(IndexRange &total_range, uint size)
{
const IndexRange indices = total_range.after(size);
total_range = IndexRange::from_begin_size(total_range.start(), total_range.size() + size);
return indices;
}
} // namespace blender
static ElemIndexRanges select_id_edit_mesh_sync(SELECTID_Instance &inst,
Object *ob,
ResourceHandle res_handle,
short select_mode,
bool draw_facedot,
const uint initial_index)
{
using namespace blender::draw;
using namespace blender;
Mesh &mesh = *static_cast<Mesh *>(ob->data);
BMEditMesh *em = mesh.runtime->edit_mesh.get();
ElemIndexRanges ranges{};
ranges.total = IndexRange::from_begin_size(initial_index, 0);
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE);
if (select_mode & SCE_SELECT_FACE) {
ranges.face = alloc_range(ranges.total, em->bm->totface);
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
PassSimple::Sub *face_sub = inst.select_face_flat;
face_sub->push_constant("offset", int(ranges.face.start()));
face_sub->draw(geom_faces, res_handle);
if (draw_facedot) {
gpu::Batch *geom_facedots = DRW_mesh_batch_cache_get_facedots_with_select_id(mesh);
face_sub->draw(geom_facedots, res_handle);
}
}
else {
if (ob->dt >= OB_SOLID) {
#ifdef USE_CAGE_OCCLUSION
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
#else
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface(mesh);
#endif
inst.select_face_uniform->draw(geom_faces, res_handle);
}
}
/* Unlike faces, only draw edges if edge select mode. */
if (select_mode & SCE_SELECT_EDGE) {
ranges.edge = alloc_range(ranges.total, em->bm->totedge);
gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh);
inst.select_edge->push_constant("offset", int(ranges.edge.start()));
inst.select_edge->draw(geom_edges, res_handle);
}
/* Unlike faces, only verts if vert select mode. */
if (select_mode & SCE_SELECT_VERTEX) {
ranges.vert = alloc_range(ranges.total, em->bm->totvert);
gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh);
inst.select_vert->push_constant("offset", int(ranges.vert.start()));
inst.select_vert->draw(geom_verts, res_handle);
}
return ranges;
}
static ElemIndexRanges select_id_mesh_sync(SELECTID_Instance &inst,
Object *ob,
ResourceHandle res_handle,
short select_mode,
const uint initial_index)
{
using namespace blender::draw;
using namespace blender;
Mesh &mesh = *static_cast<Mesh *>(ob->data);
ElemIndexRanges ranges{};
ranges.total = IndexRange::from_begin_size(initial_index, 0);
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
if (select_mode & SCE_SELECT_FACE) {
ranges.face = alloc_range(ranges.total, mesh.faces_num);
inst.select_face_flat->push_constant("offset", int(ranges.face.start()));
inst.select_face_flat->draw(geom_faces, res_handle);
}
else {
/* Only draw faces to mask out verts, we don't want their selection ID's. */
inst.select_face_uniform->draw(geom_faces, res_handle);
}
if (select_mode & SCE_SELECT_EDGE) {
ranges.edge = alloc_range(ranges.total, mesh.edges_num);
gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh);
inst.select_edge->push_constant("offset", int(ranges.edge.start()));
inst.select_edge->draw(geom_edges, res_handle);
}
if (select_mode & SCE_SELECT_VERTEX) {
ranges.vert = alloc_range(ranges.total, mesh.verts_num);
gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh);
inst.select_vert->push_constant("offset", int(ranges.vert.start()));
inst.select_vert->draw(geom_verts, res_handle);
}
return ranges;
}
static ElemIndexRanges select_id_object_sync(SELECTID_Instance &inst,
View3D *v3d,
Object *ob,
ResourceHandle res_handle,
short select_mode,
uint index_start)
{
BLI_assert_msg(index_start > 0, "Index 0 is reserved for no selection");
switch (ob->type) {
case OB_MESH: {
const Mesh &mesh = *static_cast<const Mesh *>(ob->data);
if (mesh.runtime->edit_mesh) {
bool draw_facedot = check_ob_drawface_dot(select_mode, v3d, eDrawType(ob->dt));
return select_id_edit_mesh_sync(
inst, ob, res_handle, select_mode, draw_facedot, index_start);
}
return select_id_mesh_sync(inst, ob, res_handle, select_mode, index_start);
}
case OB_CURVES_LEGACY:
case OB_SURF:
break;
}
BLI_assert_unreachable();
return ElemIndexRanges{};
}
static void select_cache_populate(void *vedata, Object *ob)
{
Manager &manager = *DRW_manager_get();
ObjectRef ob_ref = DRW_object_ref_get(ob);
SelectEngineData &e_data = get_engine_data();
SELECTID_Context &sel_ctx = e_data.context;
SELECTID_Instance &inst = *reinterpret_cast<SELECTID_Data *>(vedata)->instance;
SELECTID_ObjectData *sel_data = (SELECTID_ObjectData *)DRW_drawdata_get(
&ob->id, &draw_engine_select_type);
const DRWContextState *draw_ctx = DRW_context_state_get();
if (!sel_data || sel_data->is_drawn) {
if (sel_data) {
/* Remove data, object is not in array. */
DrawDataList *drawdata = DRW_drawdatalist_from_id(&ob->id);
BLI_freelinkN((ListBase *)drawdata, sel_data);
}
if (!sel_ctx.objects.contains(ob) && ob->dt >= OB_SOLID) {
/* This object is not selectable. It is here to participate in occlusion.
* This is the case in retopology mode. */
blender::gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface(
*static_cast<Mesh *>(ob->data));
/* This object is not in the array. It is here to participate in the depth buffer. */
if (ob->dt >= OB_SOLID) {
blender::gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface(
*static_cast<Mesh *>(ob->data));
inst.depth_occlude->draw(geom_faces, manager.resource_handle(ob_ref));
}
inst.depth_occlude->draw(geom_faces, manager.resource_handle(ob_ref));
return;
}
else if (!sel_data->in_pass) {
/* Only sync selectable object once.
* This can happen in retopology mode where there is two sync loop. */
sel_ctx.elem_ranges.lookup_or_add_cb(ob, [&]() {
ResourceHandle res_handle = manager.resource_handle(ob_ref);
const DRWContextState *draw_ctx = DRW_context_state_get();
ObjectOffsets *ob_offsets = &e_data.context.index_offsets[sel_data->drawn_index];
uint offset = e_data.context.index_drawn_len;
select_id_draw_object(inst,
draw_ctx->v3d,
ob,
res_handle,
e_data.context.select_mode,
offset,
&ob_offsets->vert,
&ob_offsets->edge,
&ob_offsets->face);
ob_offsets->offset = offset;
sel_data->in_pass = true;
e_data.context.index_drawn_len = ob_offsets->vert;
}
ElemIndexRanges elem_ranges = select_id_object_sync(
inst, draw_ctx->v3d, ob, res_handle, sel_ctx.select_mode, sel_ctx.max_index_drawn_len);
sel_ctx.max_index_drawn_len = elem_ranges.total.one_after_last();
return elem_ranges;
});
}
static void select_draw_scene(void *vedata)
@@ -297,14 +458,6 @@ static void select_draw_scene(void *vedata)
if (e_data.context.select_mode & SCE_SELECT_VERTEX) {
manager.submit(inst.select_id_vert_ps, inst.view_verts);
}
/* Mark objects from the array to later identify which ones are not in the array. */
for (Object *obj_eval : e_data.context.objects) {
DrawData *data = DRW_drawdata_ensure(
&obj_eval->id, &draw_engine_select_type, sizeof(SELECTID_ObjectData), nullptr, nullptr);
SELECTID_ObjectData *sel_data = reinterpret_cast<SELECTID_ObjectData *>(data);
sel_data->is_drawn = true;
}
}
static void select_engine_free()

View File

@@ -15,6 +15,7 @@
#include "draw_view_data.hh"
#include "DRW_render.hh"
#include "DRW_select_buffer.hh"
using namespace blender::draw;
@@ -56,16 +57,3 @@ struct SELECTID_Shaders {
GPUShader *select_id_flat;
GPUShader *select_id_uniform;
};
/* `select_draw_utils.cc` */
short select_id_get_object_select_mode(Scene *scene, Object *ob);
void select_id_draw_object(SELECTID_Instance &inst,
View3D *v3d,
Object *ob,
ResourceHandle res_handle,
short select_mode,
uint initial_offset,
uint *r_vert_offset,
uint *r_edge_offset,
uint *r_face_offset);

View File

@@ -2477,7 +2477,7 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d)
if (!viewport) {
/* Selection engine requires a viewport.
* TODO(@germano): This should be done internally in the engine. */
sel_ctx->index_drawn_len = 1;
sel_ctx->max_index_drawn_len = 1;
return;
}

View File

@@ -91,7 +91,7 @@ uint *DRW_select_buffer_read(
DRW_draw_select_id(depsgraph, region, v3d);
}
if (select_ctx->index_drawn_len > 1) {
if (select_ctx->max_index_drawn_len > 1) {
BLI_assert(region->winx == GPU_texture_width(DRW_engine_select_texture_get()) &&
region->winy == GPU_texture_height(DRW_engine_select_texture_get()));
@@ -153,8 +153,8 @@ uint *DRW_select_buffer_bitmap_from_rect(
return nullptr;
}
BLI_assert(select_ctx->index_drawn_len > 0);
const uint bitmap_len = select_ctx->index_drawn_len - 1;
BLI_assert(select_ctx->max_index_drawn_len > 0);
const uint bitmap_len = select_ctx->max_index_drawn_len - 1;
BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__);
const uint *buf_iter = buf;
@@ -195,8 +195,8 @@ uint *DRW_select_buffer_bitmap_from_circle(Depsgraph *depsgraph,
return nullptr;
}
BLI_assert(select_ctx->index_drawn_len > 0);
const uint bitmap_len = select_ctx->index_drawn_len - 1;
BLI_assert(select_ctx->max_index_drawn_len > 0);
const uint bitmap_len = select_ctx->max_index_drawn_len - 1;
BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__);
const uint *buf_iter = buf;
@@ -270,8 +270,8 @@ uint *DRW_select_buffer_bitmap_from_poly(Depsgraph *depsgraph,
drw_select_mask_px_cb,
&poly_mask_data);
BLI_assert(select_ctx->index_drawn_len > 0);
const uint bitmap_len = select_ctx->index_drawn_len - 1;
BLI_assert(select_ctx->max_index_drawn_len > 0);
const uint bitmap_len = select_ctx->max_index_drawn_len - 1;
BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__);
const uint *buf_iter = buf;
@@ -398,51 +398,38 @@ uint DRW_select_buffer_find_nearest_to_point(Depsgraph *depsgraph,
* \{ */
bool DRW_select_buffer_elem_get(const uint sel_id,
uint *r_elem,
uint *r_base_index,
char *r_elem_type)
uint &r_elem,
uint &r_base_index,
char &r_elem_type)
{
SELECTID_Context *select_ctx = DRW_select_engine_context_get();
char elem_type = 0;
uint elem_id = 0;
uint base_index = 0;
for (; base_index < select_ctx->objects.size(); base_index++) {
ObjectOffsets *base_ofs = &select_ctx->index_offsets[base_index];
if (base_ofs->face > sel_id) {
elem_id = sel_id - base_ofs->face_start;
elem_type = SCE_SELECT_FACE;
break;
for (const auto &item : select_ctx->elem_ranges.items()) {
const ElemIndexRanges &ranges = item.value;
Object *ob = item.key;
if (!ranges.total.contains(sel_id)) {
continue;
}
if (base_ofs->edge > sel_id) {
elem_id = sel_id - base_ofs->edge_start;
elem_type = SCE_SELECT_EDGE;
break;
if (ranges.face.contains(sel_id)) {
r_elem = sel_id - ranges.face.start();
r_elem_type = SCE_SELECT_FACE;
r_base_index = select_ctx->objects.first_index_of(ob);
return true;
}
if (base_ofs->vert > sel_id) {
elem_id = sel_id - base_ofs->vert_start;
elem_type = SCE_SELECT_VERTEX;
break;
if (ranges.edge.contains(sel_id)) {
r_elem = sel_id - ranges.edge.start();
r_elem_type = SCE_SELECT_EDGE;
r_base_index = select_ctx->objects.first_index_of(ob);
return true;
}
if (ranges.vert.contains(sel_id)) {
r_elem = sel_id - ranges.vert.start();
r_elem_type = SCE_SELECT_VERTEX;
r_base_index = select_ctx->objects.first_index_of(ob);
return true;
}
}
if (base_index == select_ctx->objects.size()) {
return false;
}
*r_elem = elem_id;
if (r_base_index) {
*r_base_index = base_index;
}
if (r_elem_type) {
*r_elem_type = elem_type;
}
return true;
return false;
}
uint DRW_select_buffer_context_offset_for_object_elem(Depsgraph *depsgraph,
@@ -453,23 +440,17 @@ uint DRW_select_buffer_context_offset_for_object_elem(Depsgraph *depsgraph,
Object *ob_eval = DEG_get_evaluated_object(depsgraph, object);
SELECTID_ObjectData *sel_data = (SELECTID_ObjectData *)DRW_drawdata_get(
&ob_eval->id, &draw_engine_select_type);
if (!sel_data) {
return 0;
}
ObjectOffsets *base_ofs = &select_ctx->index_offsets[sel_data->drawn_index];
const ElemIndexRanges base_ofs = select_ctx->elem_ranges.lookup_default(ob_eval,
ElemIndexRanges{});
if (elem_type == SCE_SELECT_VERTEX) {
return base_ofs->vert_start;
return base_ofs.vert.start();
}
if (elem_type == SCE_SELECT_EDGE) {
return base_ofs->edge_start;
return base_ofs.edge.start();
}
if (elem_type == SCE_SELECT_FACE) {
return base_ofs->face_start;
return base_ofs.face.start();
}
BLI_assert(0);
return 0;
@@ -488,7 +469,6 @@ void DRW_select_buffer_context_create(Depsgraph *depsgraph,
SELECTID_Context *select_ctx = DRW_select_engine_context_get();
select_ctx->objects.reinitialize(bases.size());
select_ctx->index_offsets.reinitialize(bases.size());
for (const int i : bases.index_range()) {
Object *obj = bases[i]->object;

View File

@@ -249,14 +249,14 @@ void EDBM_select_mirrored(BMEditMesh *em,
static BMElem *edbm_select_id_bm_elem_get(const Span<Base *> bases,
const uint sel_id,
uint *r_base_index)
uint &r_base_index)
{
uint elem_id;
char elem_type = 0;
bool success = DRW_select_buffer_elem_get(sel_id, &elem_id, r_base_index, &elem_type);
bool success = DRW_select_buffer_elem_get(sel_id, elem_id, r_base_index, elem_type);
if (success) {
Object *obedit = bases[*r_base_index]->object;
Object *obedit = bases[r_base_index]->object;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
switch (elem_type) {
@@ -364,7 +364,7 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc,
vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test);
if (index) {
eve = (BMVert *)edbm_select_id_bm_elem_get(bases, index, &base_index);
eve = (BMVert *)edbm_select_id_bm_elem_get(bases, index, base_index);
}
else {
eve = nullptr;
@@ -594,7 +594,7 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc,
vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test);
if (index) {
eed = (BMEdge *)edbm_select_id_bm_elem_get(bases, index, &base_index);
eed = (BMEdge *)edbm_select_id_bm_elem_get(bases, index, base_index);
}
else {
eed = nullptr;
@@ -818,7 +818,7 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc,
}
if (index) {
efa = (BMFace *)edbm_select_id_bm_elem_get(bases, index, &base_index);
efa = (BMFace *)edbm_select_id_bm_elem_get(bases, index, base_index);
}
else {
efa = nullptr;