diff options
21 files changed, 585 insertions, 183 deletions
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index bfd1cf61df0..8890c137dd2 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -493,6 +493,7 @@ macro(SETUP_BLENDER_SORTED_LIBS) bf_bmesh bf_blenkernel bf_nodes + bf_rna bf_gpu bf_blenloader bf_imbuf @@ -532,7 +533,6 @@ macro(SETUP_BLENDER_SORTED_LIBS) extern_openjpeg extern_redcode ge_videotex - bf_rna bf_dna bf_blenfont bf_intern_audaspace diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index cba6f065a6f..bbcd541d265 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -418,6 +418,12 @@ class USERPREF_PT_system(Panel): col.prop(system, "use_16bit_textures") col.separator() + col.label(text="Selection") + sub = col.column() + sub.active = system.is_occlusion_query_supported() + sub.prop(system, "select_method", text="") + + col.separator() col.label(text="Anisotropic Filtering") col.prop(system, "anisotropic_filter", text="") diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt index ca2dc1b66e2..9aa17f1e503 100644 --- a/source/blender/editors/armature/CMakeLists.txt +++ b/source/blender/editors/armature/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager + ../../gpu ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/armature/SConscript b/source/blender/editors/armature/SConscript index b3c1ea2dbe9..c68045c9398 100644 --- a/source/blender/editors/armature/SConscript +++ b/source/blender/editors/armature/SConscript @@ -39,6 +39,7 @@ incs = [ '../../blenlib', '../../makesdna', '../../makesrna', + '../../gpu', '../../windowmanager', ] incs = ' '.join(incs) diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 9c3c93e4850..12d13b05ee1 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -160,7 +160,7 @@ void *get_nearest_bone(bContext *C, short findunsel, int x, int y) rect.ymin = rect.ymax = y; glInitNames(); - hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true); if (hits > 0) return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel); @@ -295,13 +295,13 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2], rect.ymin = mval[1] - 5; rect.ymax = mval[1] + 5; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true); if (hits == 0) { rect.xmin = mval[0] - 12; rect.xmax = mval[0] + 12; rect.ymin = mval[1] - 12; rect.ymax = mval[1] + 12; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true); } /* See if there are any selected bones in this group */ if (hits > 0) { diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index 475ffd23617..ba105325b97 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -53,6 +53,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "GPU_select.h" + typedef int (*GestureDetectFct)(bContext *, SK_Gesture *, SK_Sketch *); typedef void (*GestureApplyFct)(bContext *, SK_Gesture *, SK_Sketch *); @@ -493,7 +495,7 @@ static void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int gluQuadricNormals(quad, GLU_SMOOTH); if (id != -1) { - glLoadName(id); + GPU_select_load_id(id); for (i = 0; i < stk->nb_points; i++) { glPushMatrix(); @@ -1969,7 +1971,7 @@ static int sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], in rect.ymin = mval[1] - 5; rect.ymax = mval[1] + 5; - hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true); if (hits > 0) { int besthitresult = -1; @@ -2032,7 +2034,7 @@ static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch, sk_drawStroke(stk, id, NULL, -1, -1); } - glLoadName(-1); + GPU_select_load_id(-1); } else { float selected_rgb[3] = {1, 0, 0}; diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index ed68dd72c64..b0ea984d6a6 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -270,7 +270,7 @@ bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], con /* select */ #define MAXPICKBUF 10000 -short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input); +short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, bool do_nearest); /* view3d_select.c */ float ED_view3d_select_dist_px(void); diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 36c7bb404da..feac7f6ece3 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -594,7 +594,7 @@ bool mouse_mball(bContext *C, const int mval[2], bool extend, bool deselect, boo rect.ymin = mval[1] - 12; rect.ymax = mval[1] + 12; - hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true); /* does startelem exist? */ ml = mb->editelems->first; diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index 34634fc1807..4a6215df7f3 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -67,6 +67,7 @@ #include "view3d_intern.h" +#include "GPU_select.h" /* *************** Armature Drawing - Coloring API ***************************** */ @@ -551,7 +552,7 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag, /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (id != -1) - glLoadName(id | BONESEL_ROOT); + GPU_select_load_id(id | BONESEL_ROOT); if (dt <= OB_WIRE) { if (armflag & ARM_EDITMODE) { @@ -574,7 +575,7 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag, /* Draw tip point */ if (id != -1) - glLoadName(id | BONESEL_TIP); + GPU_select_load_id(id | BONESEL_TIP); if (dt <= OB_WIRE) { if (armflag & ARM_EDITMODE) { @@ -787,7 +788,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4], /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (id != -1) - glLoadName(id | BONESEL_ROOT); + GPU_select_load_id(id | BONESEL_ROOT); drawcircball(GL_LINE_LOOP, headvec, head, imat); } @@ -799,7 +800,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4], } if (id != -1) - glLoadName(id | BONESEL_TIP); + GPU_select_load_id(id | BONESEL_TIP); drawcircball(GL_LINE_LOOP, tailvec, tail, imat); @@ -830,7 +831,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4], cross_v3_v3v3(norvect, vec, imat[2]); if (id != -1) - glLoadName(id | BONESEL_BONE); + GPU_select_load_id(id | BONESEL_BONE); glBegin(GL_LINES); @@ -907,7 +908,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (id != -1) - glLoadName(id | BONESEL_ROOT); + GPU_select_load_id(id | BONESEL_ROOT); gluSphere(qobj, head, 16, 10); } @@ -918,7 +919,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co } if (id != -1) - glLoadName(id | BONESEL_TIP); + GPU_select_load_id(id | BONESEL_TIP); glTranslatef(0.0f, 0.0f, length); gluSphere(qobj, tail, 16, 10); @@ -939,7 +940,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co if (length > (head + tail)) { if (id != -1) - glLoadName(id | BONESEL_BONE); + GPU_select_load_id(id | BONESEL_BONE); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-1.0f, -1.0f); @@ -1009,7 +1010,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (G.f & G_PICKSEL) { /* no bitmap in selection mode, crashes 3d cards... */ - glLoadName(id | BONESEL_ROOT); + GPU_select_load_id(id | BONESEL_ROOT); glBegin(GL_POINTS); glVertex3f(0.0f, 0.0f, 0.0f); glEnd(); @@ -1021,7 +1022,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned } if (id != -1) - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); glBegin(GL_LINES); glVertex3f(0.0f, 0.0f, 0.0f); @@ -1031,7 +1032,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned /* tip */ if (G.f & G_PICKSEL) { /* no bitmap in selection mode, crashes 3d cards... */ - glLoadName(id | BONESEL_TIP); + GPU_select_load_id(id | BONESEL_TIP); glBegin(GL_POINTS); glVertex3f(0.0f, 1.0f, 0.0f); glEnd(); @@ -1043,7 +1044,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned /* further we send no names */ if (id != -1) - glLoadName(id & 0xFFFF); /* object tag, for bordersel optim */ + GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */ if (armflag & ARM_POSEMODE) set_pchan_glColor(PCHAN_COLOR_LINEBONE, boneflag, constflag); @@ -1161,7 +1162,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl } if (id != -1) { - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); } /* set up solid drawing */ @@ -1266,13 +1267,13 @@ static void draw_wire_bone(const short dt, int armflag, int boneflag, short cons /* this chunk not in object mode */ if (armflag & (ARM_EDITMODE | ARM_POSEMODE)) { if (id != -1) - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); draw_wire_bone_segments(pchan, bbones, length, segments); /* further we send no names */ if (id != -1) - glLoadName(id & 0xFFFF); /* object tag, for bordersel optim */ + GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */ } /* colors for modes */ @@ -1315,7 +1316,7 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag /* now draw the bone itself */ if (id != -1) { - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); } /* wire? */ @@ -1370,7 +1371,7 @@ static void draw_custom_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obje } if (id != -1) { - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); } draw_object_instance(scene, v3d, rv3d, ob, dt, armflag & ARM_POSEMODE); @@ -1812,12 +1813,12 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, index += 0x10000; /* pose bones count in higher 2 bytes only */ } - /* very very confusing... but in object mode, solid draw, we cannot do glLoadName yet, + /* very very confusing... but in object mode, solid draw, we cannot do GPU_select_load_id yet, * stick bones and/or wire custom-shapes are drawn in next loop */ if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && (draw_wire == false) && index != -1) { /* object tag, for bordersel optim */ - glLoadName(index & 0xFFFF); + GPU_select_load_id(index & 0xFFFF); index = -1; } } @@ -1883,7 +1884,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, /* stick or wire bones have not been drawn yet so don't clear object selection in this case */ if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && draw_wire && index != -1) { /* object tag, for bordersel optim */ - glLoadName(index & 0xFFFF); + GPU_select_load_id(index & 0xFFFF); index = -1; } } @@ -1926,7 +1927,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, */ if ((do_dashed & 2) && ((bone->flag & BONE_CONNECTED) == 0)) { if (arm->flag & ARM_POSEMODE) { - glLoadName(index & 0xFFFF); /* object tag, for bordersel optim */ + GPU_select_load_id(index & 0xFFFF); /* object tag, for bordersel optim */ UI_ThemeColor(TH_WIRE); } setlinestyle(3); @@ -1946,7 +1947,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, if (constflag & PCHAN_HAS_TARGET) glColor3ub(200, 120, 0); else glColor3ub(200, 200, 50); /* add theme! */ - glLoadName(index & 0xFFFF); + GPU_select_load_id(index & 0xFFFF); pchan_draw_IK_root_lines(pchan, !(do_dashed & 2)); } } @@ -1954,7 +1955,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, if (bone->flag & BONE_SELECTED) { glColor3ub(150, 200, 50); /* add theme! */ - glLoadName(index & 0xFFFF); + GPU_select_load_id(index & 0xFFFF); pchan_draw_IK_root_lines(pchan, !(do_dashed & 2)); } } @@ -2174,7 +2175,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) /* if wire over solid, set offset */ index = -1; - glLoadName(-1); + GPU_select_load_id(-1); if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { if (G.f & G_PICKSEL) index = 0; @@ -2223,7 +2224,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) /* offset to parent */ if (eBone->parent) { UI_ThemeColor(TH_WIRE_EDIT); - glLoadName(-1); /* -1 here is OK! */ + GPU_select_load_id(-1); /* -1 here is OK! */ setlinestyle(3); glBegin(GL_LINES); @@ -2240,7 +2241,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) /* restore */ if (index != -1) { - glLoadName(-1); + GPU_select_load_id(-1); } if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 82fef4a85e8..8d39632e210 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -86,6 +86,7 @@ #include "GPU_draw.h" #include "GPU_extensions.h" +#include "GPU_select.h" #include "ED_mesh.h" #include "ED_particle.h" @@ -1586,7 +1587,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D continue; if (dflag & DRAW_PICKING) - glLoadName(base->selcol + (tracknr << 16)); + GPU_select_load_id(base->selcol + (tracknr << 16)); glPushMatrix(); glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); @@ -1737,7 +1738,7 @@ static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, } if (dflag & DRAW_PICKING) - glLoadName(base->selcol); + GPU_select_load_id(base->selcol); } /* flag similar to draw_object() */ @@ -6479,7 +6480,7 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, if (G.f & G_PICKSEL) { ml->selcol1 = code; - glLoadName(code++); + GPU_select_load_id(code++); } } drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad, imat); @@ -6493,7 +6494,7 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, if (G.f & G_PICKSEL) { ml->selcol2 = code; - glLoadName(code++); + GPU_select_load_id(code++); } drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad * atanf(ml->s) / (float)M_PI_2, imat); } diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index f61f58c12db..46ea52054c5 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1194,15 +1194,32 @@ static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, c /* we want a select buffer with bones, if there are... */ /* so check three selection levels and compare */ -static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2]) +static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2], bool *p_do_nearest, bool enumerate) { rcti rect; int offs; short hits15, hits9 = 0, hits5 = 0; bool has_bones15 = false, has_bones9 = false, has_bones5 = false; - + static int last_mval[2] = {-100, -100}; + bool do_nearest = false; + View3D *v3d = vc->v3d; + + /* define if we use solid nearest select or not */ + if (v3d->drawtype > OB_WIRE) { + do_nearest = true; + if (len_manhattan_v2v2_int(mval, last_mval) < 3) { + do_nearest = false; + } + } + copy_v2_v2_int(last_mval, mval); + + if (p_do_nearest) + *p_do_nearest = do_nearest; + + do_nearest = do_nearest && !enumerate; + BLI_rcti_init(&rect, mval[0] - 14, mval[0] + 14, mval[1] - 14, mval[1] + 14); - hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); + hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, do_nearest); if (hits15 == 1) { return selectbuffer_ret_hits_15(buffer, hits15); } @@ -1211,7 +1228,7 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff offs = 4 * hits15; BLI_rcti_init(&rect, mval[0] - 9, mval[0] + 9, mval[1] - 9, mval[1] + 9); - hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect); + hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest); if (hits9 == 1) { return selectbuffer_ret_hits_9(buffer, hits15, hits9); } @@ -1220,7 +1237,7 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff offs += 4 * hits9; BLI_rcti_init(&rect, mval[0] - 5, mval[0] + 5, mval[1] - 5, mval[1] + 5); - hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect); + hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest); if (hits5 == 1) { return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); } @@ -1242,25 +1259,13 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff } /* returns basact */ -static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], - Base *startbase, bool has_bones) +static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, + Base *startbase, bool has_bones, bool do_nearest) { Scene *scene = vc->scene; View3D *v3d = vc->v3d; Base *base, *basact = NULL; - static int lastmval[2] = {-100, -100}; int a; - bool do_nearest = false; - - /* define if we use solid nearest select or not */ - if (v3d->drawtype > OB_WIRE) { - do_nearest = true; - if (ABS(mval[0] - lastmval[0]) < 3 && ABS(mval[1] - lastmval[1]) < 3) { - if (!has_bones) /* hrms, if theres bones we always do nearest */ - do_nearest = false; - } - } - lastmval[0] = mval[0]; lastmval[1] = mval[1]; if (do_nearest) { unsigned int min = 0xFFFFFFFF; @@ -1343,16 +1348,17 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) Base *basact = NULL; unsigned int buffer[4 * MAXPICKBUF]; int hits; + bool do_nearest; /* setup view context for argument to callbacks */ view3d_operator_needs_opengl(C); view3d_set_viewcontext(C, &vc); - hits = mixed_bones_object_selectbuffer(&vc, buffer, mval); + hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, false); if (hits > 0) { const bool has_bones = selectbuffer_has_bones(buffer, hits); - basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, vc.scene->base.first, has_bones); + basact = mouse_select_eval_buffer(&vc, buffer, hits, vc.scene->base.first, has_bones, do_nearest); } return basact; @@ -1439,10 +1445,11 @@ static bool mouse_select(bContext *C, const int mval[2], } else { unsigned int buffer[4 * MAXPICKBUF]; + bool do_nearest; /* if objects have posemode set, the bones are in the same selection buffer */ - hits = mixed_bones_object_selectbuffer(&vc, buffer, mval); + hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, enumerate); if (hits > 0) { /* note: bundles are handling in the same way as bones */ @@ -1453,7 +1460,7 @@ static bool mouse_select(bContext *C, const int mval[2], basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, toggle); } else { - basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, has_bones); + basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest); } if (has_bones && basact) { @@ -1511,7 +1518,7 @@ static bool mouse_select(bContext *C, const int mval[2], if (!changed) { /* fallback to regular object selection if no new bundles were selected, * allows to select object parented to reconstruction object */ - basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, 0); + basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest); } } } @@ -1873,7 +1880,7 @@ static int do_meta_box_select(ViewContext *vc, rcti *rect, bool select, bool ext unsigned int buffer[4 * MAXPICKBUF]; short hits; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect); + hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false); if (extend == false && select) BKE_mball_deselect_all(mb); @@ -1907,7 +1914,7 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool unsigned int buffer[4 * MAXPICKBUF]; short hits; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect); + hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false); /* clear flag we use to detect point was affected */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) @@ -2001,7 +2008,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b /* selection buffer now has bones potentially too, so we add MAXPICKBUF */ vbuffer = MEM_mallocN(4 * (totobj + MAXPICKBUF) * sizeof(unsigned int), "selection buffer"); - hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKBUF), rect); + hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKBUF), rect, false); /* * LOGIC NOTES (theeth): * The buffer and ListBase have the same relative order, which makes the selection diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 716f4b10fae..e51cf371a64 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -56,6 +56,7 @@ #include "BIF_glutil.h" #include "GPU_draw.h" +#include "GPU_select.h" #include "WM_api.h" #include "WM_types.h" @@ -955,6 +956,78 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d) } } +static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar, bool use_obedit_skip) +{ + short code = 1; + char dt; + short dtx; + + if (vc->obedit && vc->obedit->type == OB_MBALL) { + draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); + } + else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) { + /* if not drawing sketch, draw bones */ + if (!BDR_drawSketchNames(vc)) { + draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); + } + } + else { + Base *base; + + v3d->xray = true; /* otherwise it postpones drawing */ + for (base = scene->base.first; base; base = base->next) { + if (base->lay & v3d->lay) { + + if ((base->object->restrictflag & OB_RESTRICT_SELECT) || + (use_obedit_skip && (scene->obedit->data == base->object->data))) + { + base->selcol = 0; + } + else { + base->selcol = code; + + if (GPU_select_load_id(code)) { + draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR); + + /* we draw duplicators for selection too */ + if ((base->object->transflag & OB_DUPLI)) { + ListBase *lb; + DupliObject *dob; + Base tbase; + + tbase.flag = OB_FROMDUPLI; + lb = object_duplilist(G.main->eval_ctx, scene, base->object); + + for (dob = lb->first; dob; dob = dob->next) { + float omat[4][4]; + + tbase.object = dob->ob; + copy_m4_m4(omat, dob->ob->obmat); + copy_m4_m4(dob->ob->obmat, dob->mat); + + /* extra service: draw the duplicator in drawtype of parent */ + /* MIN2 for the drawtype to allow bounding box objects in groups for lods */ + dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); + dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx; + + draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR); + + tbase.object->dt = dt; + tbase.object->dtx = dtx; + + copy_m4_m4(dob->ob->obmat, omat); + } + free_object_duplilist(lb); + } + } + code++; + } + } + } + v3d->xray = false; /* restore */ + } +} + /** * \warning be sure to account for a negative return value * This is an error, "Too many objects in select buffer" @@ -962,17 +1035,16 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d) * * \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) +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 code, hits; - char dt; - short dtx; + rctf rect, selrect; + 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 */ @@ -985,6 +1057,8 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b else { BLI_rctf_rcti_copy(&rect, input); } + + selrect = rect; view3d_winmatrix_set(ar, v3d, &rect); mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat); @@ -997,78 +1071,24 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b if (vc->rv3d->rflag & RV3D_CLIPPING) ED_view3d_clipping_set(vc->rv3d); - glSelectBuffer(bufsize, (GLuint *)buffer); - glRenderMode(GL_SELECT); - glInitNames(); /* these two calls whatfor? It doesnt work otherwise */ - glPushName(-1); - code = 1; + if (do_passes) + GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0); + else + GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_ALL, 0); + + view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip); + + hits = GPU_select_end(); - if (vc->obedit && vc->obedit->type == OB_MBALL) { - draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); - } - else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) { - /* if not drawing sketch, draw bones */ - if (!BDR_drawSketchNames(vc)) { - draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); - } - } - else { - Base *base; - - v3d->xray = true; /* otherwise it postpones drawing */ - for (base = scene->base.first; base; base = base->next) { - if (base->lay & v3d->lay) { - - if ((base->object->restrictflag & OB_RESTRICT_SELECT) || - (use_obedit_skip && (scene->obedit->data == base->object->data))) - { - base->selcol = 0; - } - else { - base->selcol = code; - glLoadName(code); - draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR); - - /* we draw duplicators for selection too */ - if ((base->object->transflag & OB_DUPLI)) { - ListBase *lb; - DupliObject *dob; - Base tbase; - - tbase.flag = OB_FROMDUPLI; - lb = object_duplilist(G.main->eval_ctx, scene, base->object); - - for (dob = lb->first; dob; dob = dob->next) { - float omat[4][4]; - - tbase.object = dob->ob; - copy_m4_m4(omat, dob->ob->obmat); - copy_m4_m4(dob->ob->obmat, dob->mat); - - /* extra service: draw the duplicator in drawtype of parent */ - /* MIN2 for the drawtype to allow bounding box objects in groups for lods */ - dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); - dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx; - - draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR); - - tbase.object->dt = dt; - tbase.object->dtx = dtx; - - copy_m4_m4(dob->ob->obmat, omat); - } - free_object_duplilist(lb); - } - code++; - } - } - } - v3d->xray = false; /* restore */ + /* second pass, to get the closest object to camera */ + if (do_passes) { + GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits); + + view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip); + + GPU_select_end(); } - - glPopName(); /* see above (pushname) */ - hits = glRenderMode(GL_RENDER); - + G.f &= ~G_PICKSEL; view3d_winmatrix_set(ar, v3d, NULL); mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat); diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 7765dd511b4..3ad5d94efd6 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -24,6 +24,7 @@ set(INC ../../blenkernel ../../blenlib ../../bmesh + ../../gpu ../../ikplugin ../../makesdna ../../makesrna diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript index f3c8c13647a..4f47062e3a3 100644 --- a/source/blender/editors/transform/SConscript +++ b/source/blender/editors/transform/SConscript @@ -40,6 +40,7 @@ incs = [ '../../ikplugin', '../../makesdna', '../../makesrna', + '../../gpu', '../../windowmanager', ] diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 3bd191bcc43..aa215613841 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -7231,7 +7231,7 @@ void createTransData(bContext *C, TransInfo *t) } } else if (t->options & CTX_PAINT_CURVE) { - if(!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) + if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) createTransPaintCurveVerts(C, t); } else if (t->obedit) { diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 125975eb32b..2daaa102ea9 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -72,6 +72,8 @@ /* local module include */ #include "transform.h" +#include "GPU_select.h" + /* return codes for select, and drawing flags */ #define MAN_TRANS_X (1 << 0) @@ -858,8 +860,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co /* axes */ if (flagx) { if (is_picksel) { - if (flagx & MAN_SCALE_X) glLoadName(MAN_SCALE_X); - else if (flagx & MAN_TRANS_X) glLoadName(MAN_TRANS_X); + if (flagx & MAN_SCALE_X) GPU_select_load_id(MAN_SCALE_X); + else if (flagx & MAN_TRANS_X) GPU_select_load_id(MAN_TRANS_X); } else { manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); @@ -873,8 +875,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co case 1: if (flagy) { if (is_picksel) { - if (flagy & MAN_SCALE_Y) glLoadName(MAN_SCALE_Y); - else if (flagy & MAN_TRANS_Y) glLoadName(MAN_TRANS_Y); + if (flagy & MAN_SCALE_Y) GPU_select_load_id(MAN_SCALE_Y); + else if (flagy & MAN_TRANS_Y) GPU_select_load_id(MAN_TRANS_Y); } else { manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); @@ -888,8 +890,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co case 2: if (flagz) { if (is_picksel) { - if (flagz & MAN_SCALE_Z) glLoadName(MAN_SCALE_Z); - else if (flagz & MAN_TRANS_Z) glLoadName(MAN_TRANS_Z); + if (flagz & MAN_SCALE_Z) GPU_select_load_id(MAN_SCALE_Z); + else if (flagz & MAN_TRANS_Z) GPU_select_load_id(MAN_TRANS_Z); } else { manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); @@ -975,7 +977,7 @@ static void draw_manipulator_rotate( /* Screen aligned trackball rot circle */ if (drawflags & MAN_ROT_T) { - if (is_picksel) glLoadName(MAN_ROT_T); + if (is_picksel) GPU_select_load_id(MAN_ROT_T); else UI_ThemeColor(TH_TRANSFORM); drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat); @@ -983,7 +985,7 @@ static void draw_manipulator_rotate( /* Screen aligned view rot circle */ if (drawflags & MAN_ROT_V) { - if (is_picksel) glLoadName(MAN_ROT_V); + if (is_picksel) GPU_select_load_id(MAN_ROT_V); else UI_ThemeColor(TH_TRANSFORM); drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat); @@ -1062,7 +1064,7 @@ static void draw_manipulator_rotate( /* Z circle */ if (drawflags & MAN_ROT_Z) { preOrthoFront(ortho, matt, 2); - if (is_picksel) glLoadName(MAN_ROT_Z); + if (is_picksel) GPU_select_load_id(MAN_ROT_Z); else manipulator_setcolor(v3d, 'Z', colcode, 255); drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); postOrtho(ortho); @@ -1070,7 +1072,7 @@ static void draw_manipulator_rotate( /* X circle */ if (drawflags & MAN_ROT_X) { preOrthoFront(ortho, matt, 0); - if (is_picksel) glLoadName(MAN_ROT_X); + if (is_picksel) GPU_select_load_id(MAN_ROT_X); else manipulator_setcolor(v3d, 'X', colcode, 255); glRotatef(90.0, 0.0, 1.0, 0.0); drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); @@ -1080,7 +1082,7 @@ static void draw_manipulator_rotate( /* Y circle */ if (drawflags & MAN_ROT_Y) { preOrthoFront(ortho, matt, 1); - if (is_picksel) glLoadName(MAN_ROT_Y); + if (is_picksel) GPU_select_load_id(MAN_ROT_Y); else manipulator_setcolor(v3d, 'Y', colcode, 255); glRotatef(-90.0, 1.0, 0.0, 0.0); drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); @@ -1097,7 +1099,7 @@ static void draw_manipulator_rotate( /* Z circle */ if (drawflags & MAN_ROT_Z) { preOrthoFront(ortho, rv3d->twmat, 2); - if (is_picksel) glLoadName(MAN_ROT_Z); + if (is_picksel) GPU_select_load_id(MAN_ROT_Z); else manipulator_setcolor(v3d, 'Z', colcode, 255); partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); postOrtho(ortho); @@ -1105,7 +1107,7 @@ static void draw_manipulator_rotate( /* X circle */ if (drawflags & MAN_ROT_X) { preOrthoFront(ortho, rv3d->twmat, 0); - if (is_picksel) glLoadName(MAN_ROT_X); + if (is_picksel) GPU_select_load_id(MAN_ROT_X); else manipulator_setcolor(v3d, 'X', colcode, 255); glRotatef(90.0, 0.0, 1.0, 0.0); partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); @@ -1115,7 +1117,7 @@ static void draw_manipulator_rotate( /* Y circle */ if (drawflags & MAN_ROT_Y) { preOrthoFront(ortho, rv3d->twmat, 1); - if (is_picksel) glLoadName(MAN_ROT_Y); + if (is_picksel) GPU_select_load_id(MAN_ROT_Y); else manipulator_setcolor(v3d, 'Y', colcode, 255); glRotatef(-90.0, 1.0, 0.0, 0.0); partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); @@ -1132,7 +1134,7 @@ static void draw_manipulator_rotate( if (drawflags & MAN_ROT_Z) { preOrthoFront(ortho, rv3d->twmat, 2); glPushMatrix(); - if (is_picksel) glLoadName(MAN_ROT_Z); + if (is_picksel) GPU_select_load_id(MAN_ROT_Z); else manipulator_setcolor(v3d, 'Z', colcode, 255); partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64); @@ -1145,7 +1147,7 @@ static void draw_manipulator_rotate( if (drawflags & MAN_ROT_Y) { preOrthoFront(ortho, rv3d->twmat, 1); glPushMatrix(); - if (is_picksel) glLoadName(MAN_ROT_Y); + if (is_picksel) GPU_select_load_id(MAN_ROT_Y); else manipulator_setcolor(v3d, 'Y', colcode, 255); glRotatef(90.0, 1.0, 0.0, 0.0); @@ -1160,7 +1162,7 @@ static void draw_manipulator_rotate( if (drawflags & MAN_ROT_X) { preOrthoFront(ortho, rv3d->twmat, 0); glPushMatrix(); - if (is_picksel) glLoadName(MAN_ROT_X); + if (is_picksel) GPU_select_load_id(MAN_ROT_X); else manipulator_setcolor(v3d, 'X', colcode, 255); glRotatef(-90.0, 0.0, 1.0, 0.0); @@ -1263,7 +1265,7 @@ static void draw_manipulator_scale( int shift = 0; // XXX /* center circle, do not add to selection when shift is pressed (planar constraint) */ - if (is_picksel && shift == 0) glLoadName(MAN_SCALE_C); + if (is_picksel && shift == 0) GPU_select_load_id(MAN_SCALE_C); else manipulator_setcolor(v3d, 'C', colcode, 255); glPushMatrix(); @@ -1304,7 +1306,7 @@ static void draw_manipulator_scale( case 0: /* X cube */ if (drawflags & MAN_SCALE_X) { glTranslatef(dz, 0.0, 0.0); - if (is_picksel) glLoadName(MAN_SCALE_X); + if (is_picksel) GPU_select_load_id(MAN_SCALE_X); else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); drawsolidcube(cusize); glTranslatef(-dz, 0.0, 0.0); @@ -1313,7 +1315,7 @@ static void draw_manipulator_scale( case 1: /* Y cube */ if (drawflags & MAN_SCALE_Y) { glTranslatef(0.0, dz, 0.0); - if (is_picksel) glLoadName(MAN_SCALE_Y); + if (is_picksel) GPU_select_load_id(MAN_SCALE_Y); else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); drawsolidcube(cusize); glTranslatef(0.0, -dz, 0.0); @@ -1322,7 +1324,7 @@ static void draw_manipulator_scale( case 2: /* Z cube */ if (drawflags & MAN_SCALE_Z) { glTranslatef(0.0, 0.0, dz); - if (is_picksel) glLoadName(MAN_SCALE_Z); + if (is_picksel) GPU_select_load_id(MAN_SCALE_Z); else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); drawsolidcube(cusize); glTranslatef(0.0, 0.0, -dz); @@ -1337,7 +1339,7 @@ static void draw_manipulator_scale( if (shift) { glTranslatef(0.0, -dz, 0.0); - glLoadName(MAN_SCALE_C); + GPU_select_load_id(MAN_SCALE_C); glBegin(GL_POINTS); glVertex3f(0.0, 0.0, 0.0); glEnd(); @@ -1399,7 +1401,7 @@ static void draw_manipulator_translate( glDisable(GL_DEPTH_TEST); /* center circle, do not add to selection when shift is pressed (planar constraint) */ - if (is_picksel && shift == 0) glLoadName(MAN_TRANS_C); + if (is_picksel && shift == 0) GPU_select_load_id(MAN_TRANS_C); else manipulator_setcolor(v3d, 'C', colcode, 255); glPushMatrix(); @@ -1412,7 +1414,7 @@ static void draw_manipulator_translate( glMultMatrixf(rv3d->twmat); /* axis */ - glLoadName(-1); + GPU_select_load_id(-1); // translate drawn as last, only axis when no combo with scale, or for ghosting if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) { @@ -1435,7 +1437,7 @@ static void draw_manipulator_translate( case 0: /* Z Cone */ if (drawflags & MAN_TRANS_Z) { glTranslatef(0.0, 0.0, dz); - if (is_picksel) glLoadName(MAN_TRANS_Z); + if (is_picksel) GPU_select_load_id(MAN_TRANS_Z); else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); draw_cone(qobj, cylen, cywid); glTranslatef(0.0, 0.0, -dz); @@ -1444,7 +1446,7 @@ static void draw_manipulator_translate( case 1: /* X Cone */ if (drawflags & MAN_TRANS_X) { glTranslatef(dz, 0.0, 0.0); - if (is_picksel) glLoadName(MAN_TRANS_X); + if (is_picksel) GPU_select_load_id(MAN_TRANS_X); else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); glRotatef(90.0, 0.0, 1.0, 0.0); draw_cone(qobj, cylen, cywid); @@ -1455,7 +1457,7 @@ static void draw_manipulator_translate( case 2: /* Y Cone */ if (drawflags & MAN_TRANS_Y) { glTranslatef(0.0, dz, 0.0); - if (is_picksel) glLoadName(MAN_TRANS_Y); + if (is_picksel) GPU_select_load_id(MAN_TRANS_Y); else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); glRotatef(-90.0, 1.0, 0.0, 0.0); draw_cone(qobj, cylen, cywid); @@ -1503,7 +1505,7 @@ static void draw_manipulator_rotate_cyl( unit_m4(unitmat); - if (is_picksel) glLoadName(MAN_ROT_V); + if (is_picksel) GPU_select_load_id(MAN_ROT_V); UI_ThemeColor(TH_TRANSFORM); drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat); @@ -1556,7 +1558,7 @@ static void draw_manipulator_rotate_cyl( case 0: /* X cylinder */ if (drawflags & MAN_ROT_X) { glTranslatef(1.0, 0.0, 0.0); - if (is_picksel) glLoadName(MAN_ROT_X); + if (is_picksel) GPU_select_load_id(MAN_ROT_X); glRotatef(90.0, 0.0, 1.0, 0.0); manipulator_setcolor(v3d, 'X', colcode, 255); draw_cylinder(qobj, cylen, cywid); @@ -1567,7 +1569,7 @@ static void draw_manipulator_rotate_cyl( case 1: /* Y cylinder */ if (drawflags & MAN_ROT_Y) { glTranslatef(0.0, 1.0, 0.0); - if (is_picksel) glLoadName(MAN_ROT_Y); + if (is_picksel) GPU_select_load_id(MAN_ROT_Y); glRotatef(-90.0, 1.0, 0.0, 0.0); manipulator_setcolor(v3d, 'Y', colcode, 255); draw_cylinder(qobj, cylen, cywid); @@ -1578,7 +1580,7 @@ static void draw_manipulator_rotate_cyl( case 2: /* Z cylinder */ if (drawflags & MAN_ROT_Z) { glTranslatef(0.0, 0.0, 1.0); - if (is_picksel) glLoadName(MAN_ROT_Z); + if (is_picksel) GPU_select_load_id(MAN_ROT_Z); manipulator_setcolor(v3d, 'Z', colcode, 255); draw_cylinder(qobj, cylen, cywid); glTranslatef(0.0, 0.0, -1.0); @@ -1690,10 +1692,11 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl { View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; - rctf rect; + rctf rect, selrect; GLuint buffer[64]; // max 4 items per select, so large enuf short hits; const bool is_picksel = true; + const bool do_passes = GPU_select_query_check_active(); /* XXX check a bit later on this... (ton) */ extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect); @@ -1708,13 +1711,15 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl rect.ymin = mval[1] - hotspot; rect.ymax = mval[1] + hotspot; + selrect = rect; + view3d_winmatrix_set(ar, v3d, &rect); mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); - glSelectBuffer(64, buffer); - glRenderMode(GL_SELECT); - glInitNames(); /* these two calls whatfor? It doesn't work otherwise */ - glPushName(-2); + if (do_passes) + GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0); + else + GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_ALL, 0); /* do the drawing */ if (v3d->twtype & V3D_MANIP_ROTATE) { @@ -1726,8 +1731,23 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl if (v3d->twtype & V3D_MANIP_TRANSLATE) draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); - glPopName(); - hits = glRenderMode(GL_RENDER); + hits = GPU_select_end(); + + if (do_passes) { + GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits); + + /* do the drawing */ + if (v3d->twtype & V3D_MANIP_ROTATE) { + if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); + else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, false, is_picksel); + } + if (v3d->twtype & V3D_MANIP_SCALE) + draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); + if (v3d->twtype & V3D_MANIP_TRANSLATE) + draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); + + GPU_select_end(); + } view3d_winmatrix_set(ar, v3d, NULL); mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 739deffa519..13e46bc7de8 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -51,12 +51,14 @@ set(SRC intern/gpu_extensions.c intern/gpu_material.c intern/gpu_simple_shader.c + intern/gpu_select.c GPU_buffers.h GPU_draw.h GPU_extensions.h GPU_material.h GPU_simple_shader.h + GPU_select.h intern/gpu_codegen.h ) diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h new file mode 100644 index 00000000000..1a274e0ad9d --- /dev/null +++ b/source/blender/gpu/GPU_select.h @@ -0,0 +1,61 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Antony Riakiotakis. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_select.h + * \ingroup gpu + */ + +#ifndef __GPU_SELECT__ +#define __GPU_SELECT__ + +#include "DNA_vec_types.h" /* rcft */ +#include "BLI_sys_types.h" + +/* flags for mode of operation */ +enum { + GPU_SELECT_ALL = 1, + GPU_SELECT_NEAREST_FIRST_PASS = 2, + GPU_SELECT_NEAREST_SECOND_PASS = 3, +}; + +/* initialize and provide buffer for results */ +void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits); + +/* loads a new selection id and ends previous query, if any. In second pass of selection it also returns + * if id has been hit on the first pass already. Thus we can skip drawing un-hit objects IMPORTANT: We rely on the order of object rendering on passes to be + * the same for this to work */ +bool GPU_select_load_id(unsigned int id); + +/* cleanup and flush selection results to buffer. Return number of hits and hits in buffer. + * if dopass is true, we will do a second pass with occlusion queries to get the closest hit */ +unsigned int GPU_select_end(void); + +/* does the GPU support occlusion queries? */ +bool GPU_select_query_check_support(void); + +/* is occlusion query supported and user activated? */ +bool GPU_select_query_check_active(void); + +#endif diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c new file mode 100644 index 00000000000..2df9e603903 --- /dev/null +++ b/source/blender/gpu/intern/gpu_select.c @@ -0,0 +1,246 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Antony Riakiotakis. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_select.c + * \ingroup gpu + * + * 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 "GPU_select.h" +#include "GPU_extensions.h" + +#include "BLI_utildefines.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_userdef_types.h" + +#include <GL/glew.h> + +/* Ad hoc number of queries to allocate to skip doing many glGenQueries */ +#define ALLOC_QUERIES 200 + +typedef struct GPUQueryState { + /* 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 */ + bool query_issued; + /* array holding the OpenGL query identifiers */ + unsigned int *queries; + /* array holding the id corresponding to each query */ + unsigned int *id; + /* number of queries in *queries and *id */ + unsigned int num_of_queries; + /* index to the next query to start */ + unsigned int active_query; + /* flag to cache user preference for occlusion based selection */ + bool use_gpu_select; + /* cache on initialization */ + unsigned int *buffer; + unsigned int bufsize; + /* mode of operation */ + char mode; + unsigned int index; + int oldhits; +} GPUQueryState; + +static GPUQueryState g_query_state = {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"); + glGenQueriesARB(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_TRUE); + glDepthFunc(GL_EQUAL); + } + } +} + +bool GPU_select_load_id(unsigned int id) +{ + /* if no selection mode active, ignore */ + if(!g_query_state.select_is_active) + return true; + + if (!g_query_state.use_gpu_select) { + glLoadName(id); + } + else { + if (g_query_state.query_issued) { + glEndQueryARB(GL_SAMPLES_PASSED_ARB); + } + /* if required, allocate extra queries */ + if (g_query_state.active_query == g_query_state.num_of_queries) { + g_query_state.num_of_queries += ALLOC_QUERIES; + g_query_state.queries = MEM_reallocN(g_query_state.queries, g_query_state.num_of_queries * sizeof(*g_query_state.queries)); + g_query_state.id = MEM_reallocN(g_query_state.id, g_query_state.num_of_queries * sizeof(*g_query_state.id)); + glGenQueriesARB(ALLOC_QUERIES, &g_query_state.queries[g_query_state.active_query]); + } + + glBeginQueryARB(GL_SAMPLES_PASSED_ARB, g_query_state.queries[g_query_state.active_query]); + g_query_state.id[g_query_state.active_query] = id; + g_query_state.active_query++; + g_query_state.query_issued = true; + + if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS) { + if (g_query_state.buffer[g_query_state.index * 4 + 3] == id) { + g_query_state.index++; + return true; + } + else { + return false; + } + } + } + + return true; +} + +unsigned int GPU_select_end(void) +{ + unsigned int hits = 0; + if (!g_query_state.use_gpu_select) { + glPopName(); + hits = glRenderMode(GL_RENDER); + } + else { + int i; + + if (g_query_state.query_issued) { + glEndQueryARB(GL_SAMPLES_PASSED_ARB); + } + + for (i = 0; i < g_query_state.active_query; i++) { + unsigned int result; + glGetQueryObjectuivARB(g_query_state.queries[i], GL_QUERY_RESULT_ARB, &result); + if (result > 0) { + if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) { + if(hits < g_query_state.bufsize) { + 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] = g_query_state.id[i]; + + hits++; + } + else { + hits = -1; + break; + } + } + else { + int j; + /* search in buffer and make selected object first */ + for (j = 0; j < g_query_state.oldhits; j++) { + if (g_query_state.buffer[j * 4 + 3] == g_query_state.id[i]) { + g_query_state.buffer[j * 4 + 1] = 0; + g_query_state.buffer[j * 4 + 2] = 0; + } + } + break; + } + } + } + + glDeleteQueriesARB(g_query_state.num_of_queries, g_query_state.queries); + MEM_freeN(g_query_state.queries); + MEM_freeN(g_query_state.id); + glPopAttrib(); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + + g_query_state.select_is_active = false; + + return hits; +} + + +bool GPU_select_query_check_support(void) +{ + return GLEW_ARB_occlusion_query; +} + + +bool GPU_select_query_check_active(void) +{ + return GLEW_ARB_occlusion_query && + ((U.gpu_select_method == USER_SELECT_USE_OCCLUSION_QUERY) || + ((U.gpu_select_method == USER_SELECT_AUTO) && GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY))); +} diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index d7a33638fa2..4240d85a74d 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -491,7 +491,8 @@ typedef struct UserDef { short color_picker_type; char ipo_new; /* interpolation mode for newly added F-Curves */ char keyhandles_new; /* handle types for newly added keyframes */ - char pad1[2]; + char gpu_select_method; + char pad1; short scrcastfps; /* frame rate for screencast to be played back */ short scrcastwait; /* milliseconds between screencast snapshots */ @@ -718,6 +719,13 @@ typedef enum eOpenGL_RenderingOptions { /* USER_DISABLE_AA = (1 << 4), */ /* DEPRECATED */ } eOpenGL_RenderingOptions; +/* selection method for opengl gpu_select_method */ +typedef enum eOpenGL_SelectOptions { + USER_SELECT_AUTO = 0, + USER_SELECT_USE_OCCLUSION_QUERY = 1, + USER_SELECT_USE_SELECT_RENDERMODE = 2 +} eOpenGL_SelectOptions; + /* wm draw method */ typedef enum eWM_DrawMethod { USER_DRAW_TRIPLE = 0, diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index d43bd8c1ad4..cc1fb6f0410 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -91,6 +91,7 @@ EnumPropertyItem navigation_mode_items[] = { #include "BKE_idprop.h" #include "GPU_draw.h" +#include "GPU_select.h" #include "BLF_api.h" @@ -332,6 +333,11 @@ static void rna_UserDef_viewport_lights_update(Main *bmain, Scene *scene, Pointe rna_userdef_update(bmain, scene, ptr); } +static int rna_Scene_GPU_selection_supported(UserDef *UNUSED(U)) +{ + return GPU_select_query_check_support(); +} + static void rna_userdef_autosave_update(Main *bmain, Scene *scene, PointerRNA *ptr) { wmWindowManager *wm = bmain->wm.first; @@ -3588,7 +3594,9 @@ static void rna_def_userdef_edit(BlenderRNA *brna) static void rna_def_userdef_system(BlenderRNA *brna) { + FunctionRNA *func; PropertyRNA *prop; + PropertyRNA *parm; StructRNA *srna; static EnumPropertyItem gl_texture_clamp_items[] = { @@ -3708,6 +3716,13 @@ static void rna_def_userdef_system(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem gpu_select_method_items[] = { + {USER_SELECT_AUTO, "AUTO", 0, "Automatic", ""}, + {USER_SELECT_USE_SELECT_RENDERMODE, "GL_SELECT", 0, "OpenGL Select", ""}, + {USER_SELECT_USE_OCCLUSION_QUERY, "GL_QUERY", 0, "OpenGL Occlusion Queries", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "UserPreferencesSystem", NULL); RNA_def_struct_sdna(srna, "UserDef"); RNA_def_struct_nested(brna, srna, "UserPreferences"); @@ -3950,7 +3965,16 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_boolean_negative_sdna(prop, NULL, "text_render", USER_TEXT_DISABLE_AA); RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user interface text anti-aliased"); RNA_def_property_update(prop, 0, "rna_userdef_text_update"); - + + func = RNA_def_function(srna, "is_occlusion_query_supported", "rna_Scene_GPU_selection_supported"); + parm = RNA_def_boolean(func, "is_supported", 0, "Occlusion Query Support", "Check if GPU supports Occlusion Queries"); + RNA_def_function_return(func, parm); + + prop = RNA_def_property(srna, "select_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "gpu_select_method"); + RNA_def_property_enum_items(prop, gpu_select_method_items); + RNA_def_property_ui_text(prop, "Selection Method", "Use OpenGL occlusion queries o selection rendermode to accelerate selection"); + /* Full scene anti-aliasing */ prop = RNA_def_property(srna, "multi_sample", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "ogl_multisamples"); |