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

Reply via email to