Commit: 0aaa2b7d041bf545eb6315d85e831af051b55130 Author: Campbell Barton Date: Fri Mar 3 22:51:41 2017 +1100 Branches: temp-select-pick https://developer.blender.org/rB0aaa2b7d041bf545eb6315d85e831af051b55130
Experimental depth sorting selection Differential Revision: https://developer.blender.org/D2543 =================================================================== M source/blender/editors/include/ED_view3d.h M source/blender/editors/space_view3d/view3d_view.c M source/blender/gpu/GPU_select.h M source/blender/gpu/intern/gpu_select.c =================================================================== diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 79176d9e9c..6adc05f08d 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -301,7 +301,9 @@ bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], con /* select */ #define MAXPICKELEMS 2500 #define MAXPICKBUF (4 * MAXPICKELEMS) -short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input, bool do_nearest); +short view3d_opengl_select( + struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input, + bool do_nearest); /* view3d_select.c */ float ED_view3d_select_dist_px(void); diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 8582952d1a..1e5c42fe11 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1170,7 +1170,9 @@ static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegi * * \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection. */ -short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, bool do_nearest) +short view3d_opengl_select( + ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, + bool do_nearest) { Scene *scene = vc->scene; View3D *v3d = vc->v3d; @@ -1204,10 +1206,16 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b if (vc->rv3d->rflag & RV3D_CLIPPING) ED_view3d_clipping_set(vc->rv3d); - if (do_passes) + if (do_nearest) { + GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_DEPTH_SORT, 0); + } + else if (do_passes) { + /* XXX, this wont run currently with GPU_SELECT_NEAREST_DEPTH_SORT above */ GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0); - else + } + else { GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_ALL, 0); + } view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip); diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h index d3cb914976..33a1c62b12 100644 --- a/source/blender/gpu/GPU_select.h +++ b/source/blender/gpu/GPU_select.h @@ -39,6 +39,8 @@ enum { GPU_SELECT_ALL = 1, GPU_SELECT_NEAREST_FIRST_PASS = 2, GPU_SELECT_NEAREST_SECOND_PASS = 3, + /* test for depth sorting selection */ + GPU_SELECT_NEAREST_DEPTH_SORT = 4, }; void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const struct rctf *input, char mode, int oldhits); diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c index f78191a6f6..6d5130de6f 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -29,6 +29,10 @@ * Interface for accessing gpu-related methods for selection. The semantics will be * similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility. */ + +#include <string.h> +#include <stdlib.h> + #include "GPU_select.h" #include "GPU_extensions.h" #include "GPU_glew.h" @@ -37,12 +41,72 @@ #include "DNA_userdef_types.h" +#include "BLI_rect.h" + #include "BLI_utildefines.h" /* Ad hoc number of queries to allocate to skip doing many glGenQueries */ #define ALLOC_QUERIES 200 +typedef struct DepthID { + unsigned int id; + float depth; +} DepthID; + +static int id_depth_cmp(const void *v1, const void *v2) +{ + const DepthID *d1 = v1, *d2 = v2; + if (d1->id < d2->id) { + return -1; + } + else if (d1->id > d2->id) { + return 1; + } + else { + if (d1->depth < d2->depth) { + return -1; + } + else if (d1->depth > d2->depth) { + return 1; + } + else { + return 0; + } + } +} + +static int depth_cmp(const void *v1, const void *v2) +{ + const DepthID *d1 = v1, *d2 = v2; + if (d1->depth < d2->depth) { + return -1; + } + else if (d1->depth > d2->depth) { + return 1; + } + else { + return 0; + } +} + +/* depth sorting */ +typedef struct GPUQueryStateDepth { + unsigned int rect_len; + unsigned int *rect_id; + unsigned int *rect_depth; + /* scratch buffer, avoid allocs every time */ + unsigned int *rect_depth_test; + rcti clip_rect; + /* Pass to glReadPixels (x,y,w,h */ + int clip_readpixels[4]; + + unsigned int prev_id; + bool is_init; +} GPUQueryStateDepth; + typedef struct GPUQueryState { + GPUQueryStateDepth depth; + /* To ignore selection id calls when not initialized */ bool select_is_active; /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */ @@ -57,6 +121,8 @@ typedef struct GPUQueryState { unsigned int active_query; /* flag to cache user preference for occlusion based selection */ bool use_gpu_select; + /* experimental depth buffer picking */ + bool use_gpu_select_depth; /* cache on initialization */ unsigned int *buffer; /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/ @@ -85,12 +151,55 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const rctf *in g_query_state.index = 0; g_query_state.oldhits = oldhits; + if (!g_query_state.use_gpu_select) { glSelectBuffer(bufsize, (GLuint *)buffer); glRenderMode(GL_SELECT); glInitNames(); glPushName(-1); } + else if (mode == GPU_SELECT_NEAREST_DEPTH_SORT) { + float viewport[4]; + + glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT); + /* disable writing to the framebuffer */ + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + glClear(GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LEQUAL); + + GPUQueryStateDepth *qsd = &g_query_state.depth; + + BLI_rcti_rctf_copy(&qsd->clip_rect, input); + + glGetFloatv(GL_SCISSOR_BOX, viewport); + + qsd->clip_readpixels[0] = viewport[0]; + qsd->clip_readpixels[1] = viewport[1]; + qsd->clip_readpixels[2] = BLI_rcti_size_x(&qsd->clip_rect); + qsd->clip_readpixels[3] = BLI_rcti_size_y(&qsd->clip_rect); + + + glViewport(viewport[0], viewport[1], qsd->clip_readpixels[2], qsd->clip_readpixels[3]); + + const unsigned int rect_len = BLI_rcti_size_x(&qsd->clip_rect) * BLI_rcti_size_y(&qsd->clip_rect); + qsd->rect_len = rect_len; + + qsd->rect_id = MEM_mallocN(sizeof(unsigned int) * rect_len, __func__); + memset(qsd->rect_id, 0xff, sizeof(unsigned int) * rect_len); + + qsd->rect_depth = MEM_callocN(sizeof(unsigned int) * rect_len, __func__); + + glReadPixels(UNPACK4(qsd->clip_readpixels), GL_DEPTH_COMPONENT, GL_FLOAT, qsd->rect_depth); + + /* scratch buffer (read new values here) */ + qsd->rect_depth_test = MEM_callocN(sizeof(unsigned int) * rect_len, __func__); + + qsd->prev_id = 0; + qsd->is_init = false; + } else { float viewport[4]; @@ -147,6 +256,28 @@ bool GPU_select_load_id(unsigned int id) if (!g_query_state.use_gpu_select) { glLoadName(id); } + else if (g_query_state.mode == GPU_SELECT_NEAREST_DEPTH_SORT) { + GPUQueryStateDepth *qsd = &g_query_state.depth; + if (qsd->is_init) { + const unsigned int rect_len = qsd->rect_len; + glReadPixels(UNPACK4(qsd->clip_readpixels), GL_DEPTH_COMPONENT, GL_FLOAT, qsd->rect_depth_test); + /* perform initial memcmp since most cases the array remains unchanged */ + if (memcmp(qsd->rect_depth, qsd->rect_depth_test, rect_len * sizeof(unsigned int)) != 0) { + const unsigned int prev_id = qsd->prev_id; + const unsigned int *prev = qsd->rect_depth; + const unsigned int *curr = qsd->rect_depth_test; + unsigned int *id_ptr = qsd->rect_id; + for (unsigned int i = 0; i < rect_len; i++, curr++, prev++, id_ptr++) { + if (*curr != *prev) { + *id_ptr = prev_id; + } + } + SWAP(unsigned int *, qsd->rect_depth_test, qsd->rect_depth); + } + } + qsd->prev_id = id; + qsd->is_init = true; + } else { if (g_query_state.query_issued) { glEndQuery(GL_SAMPLES_PASSED); @@ -190,6 +321,63 @@ unsigned int GPU_select_end(void) glPopName(); hits = glRenderMode(GL_RENDER); } + else if (g_query_state.mode == GPU_SELECT_NEAREST_DEPTH_SORT) { + GPUQueryStateDepth *qsd = &g_query_state.depth; + + if (qsd->is_init) { + /* force finishing last pass */ + GPU_select_load_id(qsd->prev_id); + } + glPopAttrib(); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + unsigned int maxhits = g_query_state.bufsize / 4; + + DepthID *depth = MEM_mallocN(qsd->rect_len * sizeof(*depth), __func__); + /* unsigned int depth_last = 0; */ + unsigned int depth_len = 0; + for (unsigned int i = 0; i < qsd->rect_len; i++) { + if (qsd->rect_id[i] != 0xffffffff) { + DepthID *d = &depth[depth_len++]; + d->id = qsd->rect_id[i]; + d->depth = *((float *)&qsd->rect_depth[i]); + } + } + qsort(depth, depth_len, sizeof(DepthID), id_depth_cmp); + unsigned int id_last = 0xffffffff; + unsigned int depth_compact_len = 0; + for (unsigned int i = 0; i < depth_len; i++) { + if (depth[i].id != id_last) { + id_last = depth[i].id; + depth[depth_compact_len++] = depth[i]; + } + } + qsort(depth, depth_compact_len, sizeof(DepthID), depth_cmp); + for (unsigned int i = 0; i < depth_compact_len; i++) { + if (hits < maxhits) { + g_query_state.buffer[hits * 4] = 1; + g_query_state.buffer[hits * 4 + 1] = 0xFFFF; + g_query_state.buffer[hits * 4 + 2] = 0xFFFF; + g_query_state.buffer[hits * 4 + 3] = depth[i].id; + + hits++; + } + else { + hits = -1; + break; + } + } + + MEM_freeN(depth); + + MEM_freeN(qsd->rect_id); + MEM_freeN(qsd->rect_depth); + MEM_freeN(qsd->rect_depth_test); + + qsd->rect_id = NULL; + qsd->rect_depth = NULL; + qsd->rect_depth_test = NULL; + } else { int i; _______________________________________________ Bf-blender-cvs mailing list [email protected] https://lists.blender.org/mailman/listinfo/bf-blender-cvs
