Changeset View
Changeset View
Standalone View
Standalone View
source/blender/draw/intern/draw_select_buffer.c
| Show All 18 Lines | |||||
| /** \file | /** \file | ||||
| * \ingroup draw_engine | * \ingroup draw_engine | ||||
| * | * | ||||
| * Utilities to read id buffer created in select_engine. | * Utilities to read id buffer created in select_engine. | ||||
| */ | */ | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_array_utils.h" | |||||
| #include "BLI_bitmap.h" | #include "BLI_bitmap.h" | ||||
| #include "BLI_bitmap_draw_2d.h" | #include "BLI_bitmap_draw_2d.h" | ||||
| #include "BLI_rect.h" | #include "BLI_rect.h" | ||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #include "GPU_select.h" | #include "GPU_select.h" | ||||
| ▲ Show 20 Lines • Show All 296 Lines • ▼ Show 20 Lines | if (buf) { | ||||
| BLI_assert(0 != buf_len); | BLI_assert(0 != buf_len); | ||||
| ret = buf[0]; | ret = buf[0]; | ||||
| MEM_freeN(buf); | MEM_freeN(buf); | ||||
| } | } | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| struct SelectReadData { | |||||
| const void *val_ptr; | |||||
| uint id_min; | |||||
| uint id_max; | |||||
| uint r_index; | |||||
| }; | |||||
| static bool select_buffer_test_fn(const void *__restrict value, void *__restrict userdata) | |||||
| { | |||||
| struct SelectReadData *data = userdata; | |||||
| uint hit_id = *(uint *)value; | |||||
| if (hit_id && hit_id >= data->id_min && hit_id < data->id_max) { | |||||
| /* Start at 1 to confirm. */ | |||||
| data->val_ptr = value; | |||||
| data->r_index = (hit_id - data->id_min) + 1; | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /** | /** | ||||
| * Find the selection id closest to \a center. | * Find the selection id closest to \a center. | ||||
| * \param dist: Use to initialize the distance, | * \param dist: Use to initialize the distance, | ||||
| * when found, this value is set to the distance of the selection that's returned. | * when found, this value is set to the distance of the selection that's returned. | ||||
| */ | */ | ||||
| uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, | uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, | ||||
| struct ARegion *region, | struct ARegion *region, | ||||
| struct View3D *v3d, | struct View3D *v3d, | ||||
| const int center[2], | const int center[2], | ||||
| const uint id_min, | const uint id_min, | ||||
| const uint id_max, | const uint id_max, | ||||
| uint *dist) | uint *dist) | ||||
| { | { | ||||
| /* Smart function to sample a rect spiraling outside, nice for selection ID. */ | /* Smart function to sample a rect spiraling outside, nice for selection ID. */ | ||||
| /* Create region around center (typically the mouse cursor). | /* Create region around center (typically the mouse cursor). | ||||
| * This must be square and have an odd width, | * This must be square and have an odd width. */ | ||||
| * the spiraling algorithm does not work with arbitrary rectangles. */ | |||||
| uint index = 0; | |||||
| rcti rect; | rcti rect; | ||||
| BLI_rcti_init_pt_radius(&rect, center, *dist); | BLI_rcti_init_pt_radius(&rect, center, *dist); | ||||
| rect.xmax += 1; | rect.xmax += 1; | ||||
| rect.ymax += 1; | rect.ymax += 1; | ||||
| int width = BLI_rcti_size_x(&rect); | int width = BLI_rcti_size_x(&rect); | ||||
| int height = width; | int height = width; | ||||
| BLI_assert(width == height); | |||||
| /* Read from selection framebuffer. */ | /* Read from selection framebuffer. */ | ||||
| uint buf_len; | uint buf_len; | ||||
| const uint *buf = DRW_select_buffer_read(depsgraph, region, v3d, &rect, &buf_len); | const uint *buf = DRW_select_buffer_read(depsgraph, region, v3d, &rect, &buf_len); | ||||
| if (buf == NULL) { | if (buf == NULL) { | ||||
| return index; | return 0; | ||||
| } | |||||
| 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; | |||||
| 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; | |||||
| /* Manhattan 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; | const int shape[2] = {height, width}; | ||||
| } | const int center_yx[2] = {(height + 1) / 2, (width + 1) / 2}; | ||||
| struct SelectReadData data = {NULL, id_min, id_max, 0}; | |||||
| BLI_array_iter_spiral_square(buf, shape, center_yx, select_buffer_test_fn, &data); | |||||
| if (data.val_ptr) { | |||||
| size_t offset = ((size_t)data.val_ptr - (size_t)buf) / sizeof(*buf); | |||||
| int hit_x = offset % width; | |||||
| int hit_y = offset / width; | |||||
| *dist = (uint)(abs(hit_y - center_yx[0]) + abs(hit_x - center_yx[1])); | |||||
| } | } | ||||
| exit: | |||||
| MEM_freeN((void *)buf); | MEM_freeN((void *)buf); | ||||
| return index; | return data.r_index; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Object Utils | /** \name Object Utils | ||||
| * \{ */ | * \{ */ | ||||
| ▲ Show 20 Lines • Show All 111 Lines • Show Last 20 Lines | |||||