Beispiel #1
0
/**
 * 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;
		}
	}
}
Beispiel #2
0
/**
 * \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;
}
Beispiel #3
0
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);
		}
	}
}