Cleanup: move selection utilities into ED_select_buffer_utils

This commit is contained in:
Campbell Barton 2019-05-20 13:16:29 +10:00
parent 164b6c5b04
commit d496236f4a
7 changed files with 143 additions and 106 deletions

View File

@ -23,6 +23,7 @@
struct rcti;
/* Boolean array from selection ID's. */
uint *ED_select_buffer_bitmap_from_rect(const uint bitmap_len, const struct rcti *rect);
uint *ED_select_buffer_bitmap_from_circle(const uint bitmap_len,
const int center[2],
@ -32,4 +33,11 @@ uint *ED_select_buffer_bitmap_from_poly(const uint bitmap_len,
const int poly_len,
const rcti *rect);
/* Single result from selection ID's. */
uint ED_select_buffer_sample_point(const int center[2]);
uint ED_select_buffer_find_nearest_to_point(const int center[2],
const uint id_min,
const uint id_max,
uint *dist);
#endif /* __ED_SELECT_BUFFER_UTILS_H__ */

View File

@ -451,11 +451,8 @@ int ED_view3d_backbuf_sample_size_clamp(struct ARegion *ar, const float dist);
void ED_view3d_select_id_validate(struct ViewContext *vc);
uint ED_view3d_select_id_sample(struct ViewContext *vc, int x, int y);
uint *ED_view3d_select_id_read(int xmin, int ymin, int xmax, int ymax, uint *r_buf_len);
uint *ED_view3d_select_id_read_rect(const struct rcti *rect, uint *r_buf_len);
uint ED_view3d_select_id_read_nearest(
struct ViewContext *vc, const int mval[2], const uint min, const uint max, uint *r_dist);
bool ED_view3d_autodist(struct Depsgraph *depsgraph,
struct ARegion *ar,

View File

@ -53,6 +53,7 @@
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_select_buffer_utils.h"
#include "ED_select_utils.h"
#include "ED_view3d.h"
@ -476,7 +477,7 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc,
struct EDBMSelectID_Context *sel_id_ctx = EDBM_select_id_context_create(
vc, bases, bases_len, select_mode);
index = ED_view3d_select_id_read_nearest(vc, vc->mval, 1, UINT_MAX, &dist_px);
index = ED_select_buffer_find_nearest_to_point(vc->mval, 1, UINT_MAX, &dist_px);
if (index) {
eve = (BMVert *)EDBM_select_id_bm_elem_get(sel_id_ctx, index, &base_index);
@ -701,7 +702,7 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc,
struct EDBMSelectID_Context *sel_id_ctx = EDBM_select_id_context_create(
vc, bases, bases_len, select_mode);
index = ED_view3d_select_id_read_nearest(vc, vc->mval, 1, UINT_MAX, &dist_px);
index = ED_select_buffer_find_nearest_to_point(vc->mval, 1, UINT_MAX, &dist_px);
if (index) {
eed = (BMEdge *)EDBM_select_id_bm_elem_get(sel_id_ctx, index, &base_index);
@ -910,7 +911,7 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc,
struct EDBMSelectID_Context *sel_id_ctx = EDBM_select_id_context_create(
vc, bases, bases_len, select_mode);
index = ED_view3d_select_id_sample(vc, vc->mval[0], vc->mval[1]);
index = ED_select_buffer_sample_point(vc->mval);
if (index) {
efa = (BMFace *)EDBM_select_id_bm_elem_get(sel_id_ctx, index, &base_index);

View File

@ -61,6 +61,7 @@
#include "DEG_depsgraph_query.h"
#include "ED_mesh.h"
#include "ED_select_buffer_utils.h"
#include "ED_object.h"
#include "ED_view3d.h"
@ -1114,11 +1115,11 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px,
if (dist_px) {
/* sample rect to increase chances of selecting, so that when clicking
* on an edge in the backbuf, we can still select a face */
*r_index = ED_view3d_select_id_read_nearest(&vc, mval, 1, me->totpoly + 1, &dist_px);
*r_index = ED_select_buffer_find_nearest_to_point(mval, 1, me->totpoly + 1, &dist_px);
}
else {
/* sample only on the exact position */
*r_index = ED_view3d_select_id_sample(&vc, mval[0], mval[1]);
*r_index = ED_select_buffer_sample_point(mval);
}
if ((*r_index) == 0 || (*r_index) > (unsigned int)me->totpoly) {
@ -1295,11 +1296,11 @@ bool ED_mesh_pick_vert(
if (dist_px > 0) {
/* sample rect to increase chances of selecting, so that when clicking
* on an face in the backbuf, we can still select a vert */
*r_index = ED_view3d_select_id_read_nearest(&vc, mval, 1, me->totvert + 1, &dist_px);
*r_index = ED_select_buffer_find_nearest_to_point(mval, 1, me->totvert + 1, &dist_px);
}
else {
/* sample only on the exact position */
*r_index = ED_view3d_select_id_sample(&vc, mval[0], mval[1]);
*r_index = ED_select_buffer_sample_point(mval);
}
if ((*r_index) == 0 || (*r_index) > (uint)me->totvert) {

View File

@ -71,6 +71,7 @@
#include "BLI_sys_types.h"
#include "ED_mesh.h" /* for face mask functions */
#include "ED_select_buffer_utils.h"
#include "WM_api.h"
#include "WM_types.h"
@ -390,7 +391,7 @@ static int imapaint_pick_face(ViewContext *vc,
/* sample only on the exact position */
ED_view3d_select_id_validate(vc);
*r_index = ED_view3d_select_id_sample(vc, mval[0], mval[1]);
*r_index = ED_select_buffer_sample_point(mval);
if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) {
return 0;

View File

@ -277,22 +277,6 @@ int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist)
return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx));
}
/* samples a single pixel (copied from vpaint) */
uint ED_view3d_select_id_sample(ViewContext *vc, int x, int y)
{
if (x >= vc->ar->winx || y >= vc->ar->winy) {
return 0;
}
uint buf_len;
uint *buf = ED_view3d_select_id_read(x, y, x, y, &buf_len);
BLI_assert(0 != buf_len);
uint ret = buf[0];
MEM_freeN(buf);
return ret;
}
/* reads full rect, converts indices */
uint *ED_view3d_select_id_read(int xmin, int ymin, int xmax, int ymax, uint *r_buf_len)
{
@ -317,85 +301,6 @@ uint *ED_view3d_select_id_read(int xmin, int ymin, int xmax, int ymax, uint *r_b
return buf;
}
/* smart function to sample a rect spiralling outside, nice for backbuf selection */
uint ED_view3d_select_id_read_nearest(struct ViewContext *UNUSED(vc),
const int mval[2],
const uint id_min,
const uint id_max,
uint *r_dist)
{
/* Create region around mouse cursor. This must be square and have an odd
* width, the spiraling algorithm does not work with arbitrary rectangles. */
rcti rect;
BLI_rcti_init_pt_radius(&rect, mval, *r_dist);
rect.xmax += 1;
rect.ymax += 1;
int width = BLI_rcti_size_x(&rect);
int height = width;
BLI_assert(width == height);
/* Read from selection framebuffer. */
uint *buf = MEM_mallocN(width * height * sizeof(*buf), __func__);
DRW_framebuffer_select_id_read(&rect, buf);
/* Spiral, starting from center of buffer. */
int spiral_offset = height * (int)(width / 2) + (height / 2);
int spiral_direction = 0;
uint index = 0;
for (int nr = 1; nr <= height; nr++) {
for (int a = 0; a < 2; a++) {
for (int b = 0; b < nr; b++) {
/* Find hit within the specified range. */
uint hit_id = buf[spiral_offset];
if (hit_id && hit_id >= id_min && hit_id < id_max) {
/* Get x/y from spiral offset. */
int hit_x = spiral_offset % width;
int hit_y = spiral_offset / width;
int center_x = width / 2;
int center_y = height / 2;
/* Manhatten distance in keeping with other screen-based selection. */
*r_dist = (uint)(abs(hit_x - center_x) + abs(hit_y - center_y));
/* Indices start at 1 here. */
index = (hit_id - id_min) + 1;
goto exit;
}
/* Next spiral step. */
if (spiral_direction == 0) {
spiral_offset += 1; /* right */
}
else if (spiral_direction == 1) {
spiral_offset -= width; /* down */
}
else if (spiral_direction == 2) {
spiral_offset -= 1; /* left */
}
else {
spiral_offset += width; /* up */
}
/* Stop if we are outside the buffer. */
if (spiral_offset < 0 || spiral_offset >= width * height) {
goto exit;
}
}
spiral_direction = (spiral_direction + 1) % 4;
}
}
exit:
MEM_freeN(buf);
return index;
}
/* ************************************************************* */
static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)

View File

@ -19,6 +19,11 @@
/** \file
* \ingroup edutil
*
* Generic utilities for handling buffer selection where selection ID's are drawn onto
* an off screen buffer.
*
* All coordinates are relative to the current region.
*/
#include "MEM_guardedalloc.h"
@ -35,6 +40,14 @@
* way to read from selection buffers that doesn't depend on the view3d API. */
#include "ED_view3d.h"
/* -------------------------------------------------------------------- */
/** \name Select Bitmap from ID's
*
* Given a buffer of select ID's, fill in a booleans (true/false) per index.
* #BLI_bitmap is used for memory effeciency.
*
* \{ */
/**
* \param bitmap_len: Number of indices in the selection id buffer.
* \param rect: The rectangle to sample indices from (min/max inclusive).
@ -177,3 +190,114 @@ uint *ED_select_buffer_bitmap_from_poly(const uint bitmap_len,
return bitmap_buf;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Find Single Select ID's
*
* Given a buffer of select ID's, find the a single select id.
*
* \{ */
/**
* Samples a single pixel.
*/
uint ED_select_buffer_sample_point(const int center[2])
{
uint buf_len;
uint *buf = ED_view3d_select_id_read(center[0], center[1], center[0], center[1], &buf_len);
BLI_assert(0 != buf_len);
uint ret = buf[0];
MEM_freeN(buf);
return ret;
}
/**
* Find the selection id closest to \a center.
* \param dist[in,out]: Use to initalize the distance,
* when found, this value is set to the distance of the selection thats returned.
*/
uint ED_select_buffer_find_nearest_to_point(const int center[2],
const uint id_min,
const uint id_max,
uint *dist)
{
/* Smart function to sample a rect spiralling outside, nice for selection ID. */
/* Create region around center (typically the mouse cursor).
* This must be square and have an odd width,
* the spiraling algorithm does not work with arbitrary rectangles. */
rcti rect;
BLI_rcti_init_pt_radius(&rect, center, *dist);
rect.xmax += 1;
rect.ymax += 1;
int width = BLI_rcti_size_x(&rect);
int height = width;
BLI_assert(width == height);
/* Read from selection framebuffer. */
uint buf_len;
const uint *buf = ED_view3d_select_id_read_rect(&rect, &buf_len);
BLI_assert(width * height == buf_len);
/* Spiral, starting from center of buffer. */
int spiral_offset = height * (int)(width / 2) + (height / 2);
int spiral_direction = 0;
uint index = 0;
for (int nr = 1; nr <= height; nr++) {
for (int a = 0; a < 2; a++) {
for (int b = 0; b < nr; b++) {
/* Find hit within the specified range. */
uint hit_id = buf[spiral_offset];
if (hit_id && hit_id >= id_min && hit_id < id_max) {
/* Get x/y from spiral offset. */
int hit_x = spiral_offset % width;
int hit_y = spiral_offset / width;
int center_x = width / 2;
int center_y = height / 2;
/* Manhatten distance in keeping with other screen-based selection. */
*dist = (uint)(abs(hit_x - center_x) + abs(hit_y - center_y));
/* Indices start at 1 here. */
index = (hit_id - id_min) + 1;
goto exit;
}
/* Next spiral step. */
if (spiral_direction == 0) {
spiral_offset += 1; /* right */
}
else if (spiral_direction == 1) {
spiral_offset -= width; /* down */
}
else if (spiral_direction == 2) {
spiral_offset -= 1; /* left */
}
else {
spiral_offset += width; /* up */
}
/* Stop if we are outside the buffer. */
if (spiral_offset < 0 || spiral_offset >= buf_len) {
goto exit;
}
}
spiral_direction = (spiral_direction + 1) % 4;
}
}
exit:
MEM_freeN((void *)buf);
return index;
}
/** \} */