/** * initialize and provide buffer for results */ void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, int oldhits) { if (mode == GPU_SELECT_NEAREST_SECOND_PASS) { /* In the case hits was '-1', don't start the second pass since it's not going to give useful results. * As well as buffer overflow in 'gpu_select_query_load_id'. */ BLI_assert(oldhits != -1); } g_select_state.select_is_active = true; g_select_state.use_gpu_select = GPU_select_query_check_active(); g_select_state.mode = mode; if (ELEM(g_select_state.mode, GPU_SELECT_PICK_ALL, GPU_SELECT_PICK_NEAREST)) { g_select_state.algorithm = ALGO_GL_PICK; } else if (!g_select_state.use_gpu_select) { g_select_state.algorithm = ALGO_GL_LEGACY; } else { g_select_state.algorithm = ALGO_GL_QUERY; } switch (g_select_state.algorithm) { case ALGO_GL_LEGACY: { g_select_state.use_cache = false; glSelectBuffer(bufsize, (GLuint *)buffer); glRenderMode(GL_SELECT); glInitNames(); glPushName(-1); break; } case ALGO_GL_QUERY: { g_select_state.use_cache = false; gpu_select_query_begin((uint (*)[4])buffer, bufsize / 4, input, mode, oldhits); break; } default: /* ALGO_GL_PICK */ { gpu_select_pick_begin((uint (*)[4])buffer, bufsize / 4, input, mode); break; } } }
/** * \warning be sure to account for a negative return value * This is an error, "Too many objects in select buffer" * and no action should be taken (can crash blender) if this happens * * \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) { Scene *scene = vc->scene; View3D *v3d = vc->v3d; ARegion *ar = vc->ar; rctf rect; short hits; const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL); const bool do_passes = do_nearest && GPU_select_query_check_active(); G.f |= G_PICKSEL; /* case not a border select */ if (input->xmin == input->xmax) { rect.xmin = input->xmin - 12; /* seems to be default value for bones only now */ rect.xmax = input->xmin + 12; rect.ymin = input->ymin - 12; rect.ymax = input->ymin + 12; } else { BLI_rctf_rcti_copy(&rect, input); } view3d_winmatrix_set(ar, v3d, &rect); mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat); if (v3d->drawtype > OB_WIRE) { v3d->zbuf = true; glEnable(GL_DEPTH_TEST); } if (vc->rv3d->rflag & RV3D_CLIPPING) ED_view3d_clipping_set(vc->rv3d); if (do_passes) GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0); else GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_ALL, 0); view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip); hits = GPU_select_end(); /* second pass, to get the closest object to camera */ if (do_passes) { GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip); GPU_select_end(); } G.f &= ~G_PICKSEL; view3d_winmatrix_set(ar, v3d, NULL); mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat); if (v3d->drawtype > OB_WIRE) { v3d->zbuf = 0; glDisable(GL_DEPTH_TEST); } // XXX persp(PERSP_WIN); if (vc->rv3d->rflag & RV3D_CLIPPING) ED_view3d_clipping_disable(); if (hits < 0) printf("Too many objects in select buffer\n"); /* XXX make error message */ return hits; }
void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits) { g_query_state.select_is_active = true; g_query_state.query_issued = false; g_query_state.active_query = 0; g_query_state.use_gpu_select = GPU_select_query_check_active(); g_query_state.num_of_queries = 0; g_query_state.bufsize = bufsize; g_query_state.buffer = buffer; g_query_state.mode = mode; 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 { float viewport[4]; g_query_state.num_of_queries = ALLOC_QUERIES; g_query_state.queries = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.queries), "gpu selection queries"); g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id), "gpu selection ids"); glGenQueries(g_query_state.num_of_queries, g_query_state.queries); glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT); /* disable writing to the framebuffer */ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); /* In order to save some fill rate we minimize the viewport using rect. * We need to get the region of the scissor so that our geometry doesn't * get rejected before the depth test. Should probably cull rect against * scissor for viewport but this is a rare case I think */ glGetFloatv(GL_SCISSOR_BOX, viewport); if (!input || input->xmin == input->xmax) { glViewport(viewport[0], viewport[1], 24, 24); } else { glViewport(viewport[0], viewport[1], (int)(input->xmax - input->xmin), (int)(input->ymax - input->ymin)); } /* occlusion queries operates on fragments that pass tests and since we are interested on all * objects in the view frustum independently of their order, we need to disable the depth test */ if (mode == GPU_SELECT_ALL) { glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); } else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) { glClear(GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_LEQUAL); } else if (mode == GPU_SELECT_NEAREST_SECOND_PASS) { glEnable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); glDepthFunc(GL_EQUAL); } } }