diff options
Diffstat (limited to 'source/blender/editors')
29 files changed, 1608 insertions, 904 deletions
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 787cf7f0524..dfa5a51a775 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -226,9 +226,14 @@ typedef struct MirrTopoStore_t { bool ED_mesh_mirrtopo_recalc_check( struct Mesh *me, struct DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store); +bool ED_mesh_mirrtopo_recalc_check__real_mesh( + struct Mesh *me, struct Mesh *dm, MirrTopoStore_t *mesh_topo_store); void ED_mesh_mirrtopo_init( struct Mesh *me, struct DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store, const bool skip_em_vert_array_init); +void ED_mesh_mirrtopo_init__real_mesh( + struct Mesh *me, struct Mesh *dm, MirrTopoStore_t *mesh_topo_store, + const bool skip_em_vert_array_init); void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store); @@ -318,16 +323,21 @@ int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op); /* mirror lookup api */ int ED_mesh_mirror_spatial_table( struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm, const float co[3], char mode); +int ED_mesh_mirror_spatial_table__real_mesh( + struct Object *ob, struct BMEditMesh *em, struct Mesh *mesh, const float co[3], char mode); int ED_mesh_mirror_topo_table(struct Object *ob, struct DerivedMesh *dm, char mode); +int ED_mesh_mirror_topo_table__real_mesh(struct Object *ob, struct Mesh *mesh, char mode); /* retrieves mirrored cache vert, or NULL if there isn't one. * note: calling this without ensuring the mirror cache state * is bad.*/ int mesh_get_x_mirror_vert(struct Object *ob, struct DerivedMesh *dm, int index, const bool use_topology); +int mesh_get_x_mirror_vert__real_mesh(struct Object *ob, struct Mesh *mesh, int index, const bool use_topology); struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh *em, struct BMVert *eve, const float co[3], int index, const bool use_topology); int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm); +int *mesh_get_x_mirror_faces__real_mesh(struct Object *ob, struct BMEditMesh *em, struct Mesh *mesh); int ED_mesh_mirror_get_vert(struct Object *ob, int index); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 4b22e691885..3d17afc2878 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -173,7 +173,7 @@ void ED_screen_update_after_scene_change( const struct bScreen *screen, struct Scene *scene_new, struct ViewLayer *view_layer); -void ED_screen_set_active_region(struct bContext *C, const int xy[2]); +void ED_screen_set_active_region(struct bContext *C, struct wmWindow *win, const int xy[2]); void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen); void ED_screen_animation_timer(struct bContext *C, int redraws, int refresh, int sync, int enable); void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh); diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index 465a91ad0d0..d65679e1872 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -119,7 +119,6 @@ bool ED_transform_snap_object_project_view3d_ex( const unsigned short snap_to, const struct SnapObjectParams *params, const float mval[2], float *dist_px, - float *ray_depth, float r_loc[3], float r_no[3], int *r_index, struct Object **r_ob, float r_obmat[4][4]); bool ED_transform_snap_object_project_view3d( @@ -127,7 +126,6 @@ bool ED_transform_snap_object_project_view3d( const unsigned short snap_to, const struct SnapObjectParams *params, const float mval[2], float *dist_px, - float *ray_depth, /* return args */ float r_loc[3], float r_no[3]); bool ED_transform_snap_object_project_view3d_mixed( diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index ca5af7a535d..e75b133b5bd 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -37,6 +37,7 @@ #include "BKE_global.h" #include "BKE_editmesh.h" #include "BKE_unit.h" +#include "BKE_layer.h" #include "RNA_define.h" #include "RNA_access.h" @@ -77,15 +78,22 @@ static const float value_scale_per_inch[NUM_VALUE_KINDS] = { 0.0f, 100.0f, 1.0f, typedef struct { BMEditMesh *em; + BMBackup mesh_backup; +} BevelObjectStore; + + +typedef struct { float initial_length[NUM_VALUE_KINDS]; float scale[NUM_VALUE_KINDS]; NumInput num_input[NUM_VALUE_KINDS]; float shift_value[NUM_VALUE_KINDS]; /* The current value when shift is pressed. Negative when shift not active. */ bool is_modal; + BevelObjectStore *ob_store; + uint ob_store_len; + /* modal only */ float mcenter[2]; - BMBackup mesh_backup; void *draw_handle_pixel; short twflag; short value_mode; /* Which value does mouse movement and numeric input affect? */ @@ -128,24 +136,35 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op) static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) { - Object *obedit = CTX_data_edit_object(C); Scene *scene = CTX_data_scene(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); BevelData *opdata; + ViewLayer *view_layer = CTX_data_view_layer(C); float pixels_per_inch; int i; - if (em->bm->totvertsel == 0) { - return false; - } - if (is_modal) { RNA_float_set(op->ptr, "offset", 0.0f); } op->customdata = opdata = MEM_mallocN(sizeof(BevelData), "beveldata_mesh_operator"); + uint objects_used_len = 0; + + { + uint ob_store_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &ob_store_len); + opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__); + for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totvertsel > 0) { + opdata->ob_store[objects_used_len].em = em; + objects_used_len++; + } + } + MEM_freeN(objects); + opdata->ob_store_len = objects_used_len; + } - opdata->em = em; opdata->is_modal = is_modal; opdata->value_mode = OFFSET_VALUE; opdata->segments = (float) RNA_int_get(op->ptr, "segments"); @@ -174,7 +193,9 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); - opdata->mesh_backup = EDBM_redo_state_store(em); + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + opdata->ob_store[ob_index].mesh_backup = EDBM_redo_state_store(opdata->ob_store[ob_index].em); + } opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); G.moving = G_TRANSFORM_EDIT; @@ -191,8 +212,10 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) static bool edbm_bevel_calc(wmOperator *op) { BevelData *opdata = op->customdata; - BMEditMesh *em = opdata->em; + BMEditMesh *em; BMOperator bmop; + bool changed = false; + const float offset = RNA_float_get(op->ptr, "offset"); const int offset_type = RNA_enum_get(op->ptr, "offset_type"); const int segments = RNA_int_get(op->ptr, "segments"); @@ -202,40 +225,45 @@ static bool edbm_bevel_calc(wmOperator *op) int material = RNA_int_get(op->ptr, "material"); const bool loop_slide = RNA_boolean_get(op->ptr, "loop_slide"); - /* revert to original mesh */ - if (opdata->is_modal) { - EDBM_redo_state_restore(opdata->mesh_backup, em, false); - } - if (em->ob) { - material = CLAMPIS(material, -1, em->ob->totcol - 1); - } + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + em = opdata->ob_store[ob_index].em; - EDBM_op_init(em, &bmop, op, - "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b " - "material=%i loop_slide=%b", - BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, - clamp_overlap, material, loop_slide); + /* revert to original mesh */ + if (opdata->is_modal) { + EDBM_redo_state_restore(opdata->ob_store[ob_index].mesh_backup, em, false); + } - BMO_op_exec(em->bm, &bmop); + if (em->ob) { + material = CLAMPIS(material, -1, em->ob->totcol - 1); + } - if (offset != 0.0f) { - /* not essential, but we may have some loose geometry that - * won't get bevel'd and better not leave it selected */ - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); - } + EDBM_op_init(em, &bmop, op, + "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b " + "material=%i loop_slide=%b", + BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, + clamp_overlap, material, loop_slide); - /* no need to de-select existing geometry */ - if (!EDBM_op_finish(em, &bmop, op, true)) { - return false; - } + BMO_op_exec(em->bm, &bmop); - EDBM_mesh_normals_update(opdata->em); + if (offset != 0.0f) { + /* not essential, but we may have some loose geometry that + * won't get bevel'd and better not leave it selected */ + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + } + + /* no need to de-select existing geometry */ + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } - EDBM_update_generic(opdata->em, true, true); + EDBM_mesh_normals_update(em); - return true; + EDBM_update_generic(em, true, true); + changed = true; + } + return changed; } static void edbm_bevel_exit(bContext *C, wmOperator *op) @@ -251,14 +279,17 @@ static void edbm_bevel_exit(bContext *C, wmOperator *op) if (opdata->is_modal) { View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); - EDBM_redo_state_free(&opdata->mesh_backup, NULL, false); + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, NULL, false); + } ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel); if (v3d) { v3d->twflag = opdata->twflag; } G.moving = 0; } - MEM_freeN(opdata); + MEM_SAFE_FREE(opdata->ob_store); + MEM_SAFE_FREE(op->customdata); op->customdata = NULL; } @@ -266,8 +297,10 @@ static void edbm_bevel_cancel(bContext *C, wmOperator *op) { BevelData *opdata = op->customdata; if (opdata->is_modal) { - EDBM_redo_state_free(&opdata->mesh_backup, opdata->em, true); - EDBM_update_generic(opdata->em, false, true); + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, opdata->ob_store[ob_index].em, true); + EDBM_update_generic(opdata->ob_store[ob_index].em, false, true); + } } edbm_bevel_exit(C, op); diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index d681d904e74..4d76dba4c3a 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -33,6 +33,7 @@ #include "BLI_kdopbvh.h" #include "BLI_linklist_stack.h" +#include "BKE_layer.h" #include "BKE_editmesh_bvh.h" #include "BKE_context.h" #include "BKE_report.h" @@ -146,9 +147,6 @@ enum { static int edbm_intersect_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; const int mode = RNA_enum_get(op->ptr, "mode"); int (*test_fn)(BMFace *, void *); bool use_separate_all = false; @@ -186,29 +184,45 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op) default: /* ISECT_SEPARATE_NONE */ break; } + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + uint isect_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - has_isect = BM_mesh_intersect( - bm, - em->looptris, em->tottri, - test_fn, NULL, - use_self, use_separate_all, true, true, true, - -1, - eps); - - if (use_separate_cut) { - /* detach selected/un-selected faces */ - BM_mesh_separate_faces( - bm, - BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT)); - } + if (em->bm->totfacesel == 0) { + continue; + } + + has_isect = BM_mesh_intersect( + em->bm, + em->looptris, em->tottri, + test_fn, NULL, + use_self, use_separate_all, true, true, true, + -1, + eps); + + if (use_separate_cut) { + /* detach selected/un-selected faces */ + BM_mesh_separate_faces( + em->bm, + BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT)); + } - if (has_isect) { - edbm_intersect_select(em); + if (has_isect) { + edbm_intersect_select(em); + } + else { + isect_len++; + } } - else { + MEM_freeN(objects); + + if (isect_len == objects_len) { BKE_report(op->reports, RPT_WARNING, "No intersections found"); } - return OPERATOR_FINISHED; } @@ -266,9 +280,6 @@ void MESH_OT_intersect(struct wmOperatorType *ot) static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; const int boolean_operation = RNA_enum_get(op->ptr, "operation"); bool use_swap = RNA_boolean_get(op->ptr, "use_swap"); const float eps = RNA_float_get(op->ptr, "threshold"); @@ -276,23 +287,39 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op) bool has_isect; test_fn = use_swap ? bm_face_isect_pair_swap : bm_face_isect_pair; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + uint isect_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totfacesel == 0) { + continue; + } - has_isect = BM_mesh_intersect( - bm, - em->looptris, em->tottri, - test_fn, NULL, - false, false, true, true, true, - boolean_operation, - eps); + has_isect = BM_mesh_intersect( + em->bm, + em->looptris, em->tottri, + test_fn, NULL, + false, false, true, true, true, + boolean_operation, + eps); - if (has_isect) { - edbm_intersect_select(em); + if (has_isect) { + edbm_intersect_select(em); + } + else { + isect_len++; + } } - else { + MEM_freeN(objects); + + if (isect_len == objects_len) { BKE_report(op->reports, RPT_WARNING, "No intersections found"); } - return OPERATOR_FINISHED; } @@ -652,257 +679,270 @@ static BMEdge *bm_face_split_edge_find( static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; const char hflag = BM_ELEM_TAG; BMEdge *e; BMIter iter; - BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; - { - BMVert *v; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BM_elem_flag_disable(v, hflag); + if ((bm->totedgesel == 0) || + (bm->totfacesel == 0)) + { + continue; } - } - - /* edge index is set to -1 then used to assosiate them with faces */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { - BM_elem_flag_enable(e, hflag); - BM_elem_flag_enable(e->v1, hflag); - BM_elem_flag_enable(e->v2, hflag); + BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *); + { + BMVert *v; + BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { + BM_elem_flag_disable(v, hflag); + } } - else { - BM_elem_flag_disable(e, hflag); - } - BM_elem_index_set(e, -1); /* set_dirty */ - } - bm->elem_index_dirty |= BM_EDGE; - { - BMFace *f; - int i; - BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - BM_elem_flag_enable(f, hflag); + /* edge index is set to -1 then used to assosiate them with faces */ + BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { + BM_elem_flag_enable(e, hflag); + + BM_elem_flag_enable(e->v1, hflag); + BM_elem_flag_enable(e->v2, hflag); + } else { - BM_elem_flag_disable(f, hflag); + BM_elem_flag_disable(e, hflag); } - BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG); - BM_elem_index_set(f, i); /* set_ok */ + BM_elem_index_set(e, -1); /* set_dirty */ } - } - bm->elem_index_dirty &= ~BM_FACE; - - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, hflag)) { - BMIter viter; - BMVert *v; - BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { - BMIter liter; - BMLoop *l; - - unsigned int loop_stack_len; - BMLoop *l_best = NULL; - - BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack)); - loop_stack_len = 0; - - BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { - if (BM_elem_flag_test(l->f, hflag)) { - BLI_SMALLSTACK_PUSH(loop_stack, l); - loop_stack_len++; - } - } + bm->elem_index_dirty |= BM_EDGE; - if (loop_stack_len == 0) { - /* pass */ - } - else if (loop_stack_len == 1) { - l_best = BLI_SMALLSTACK_POP(loop_stack); + { + BMFace *f; + int i; + BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_elem_flag_enable(f, hflag); } else { - /* complicated case, match the edge with a face-loop */ + BM_elem_flag_disable(f, hflag); + } + BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG); + BM_elem_index_set(f, i); /* set_ok */ + } + } + bm->elem_index_dirty &= ~BM_FACE; + + BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, hflag)) { + BMIter viter; + BMVert *v; + BM_ITER_ELEM(v, &viter, e, BM_VERTS_OF_EDGE) { + BMIter liter; + BMLoop *l; + + unsigned int loop_stack_len; + BMLoop *l_best = NULL; + + BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack)); + loop_stack_len = 0; + + BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) { + if (BM_elem_flag_test(l->f, hflag)) { + BLI_SMALLSTACK_PUSH(loop_stack, l); + loop_stack_len++; + } + } + + if (loop_stack_len == 0) { + /* pass */ + } + else if (loop_stack_len == 1) { + l_best = BLI_SMALLSTACK_POP(loop_stack); + } + else { + /* complicated case, match the edge with a face-loop */ - BMVert *v_other = BM_edge_other_vert(e, v); - float e_dir[3]; + BMVert *v_other = BM_edge_other_vert(e, v); + float e_dir[3]; - /* we want closest to zero */ - float dot_best = FLT_MAX; + /* we want closest to zero */ + float dot_best = FLT_MAX; - sub_v3_v3v3(e_dir, v_other->co, v->co); - normalize_v3(e_dir); + sub_v3_v3v3(e_dir, v_other->co, v->co); + normalize_v3(e_dir); - while ((l = BLI_SMALLSTACK_POP(loop_stack))) { - float dot_test; + while ((l = BLI_SMALLSTACK_POP(loop_stack))) { + float dot_test; - /* Check dot first to save on expensive angle-comparison. - * ideal case is 90d difference == 0.0 dot */ - dot_test = fabsf(dot_v3v3(e_dir, l->f->no)); - if (dot_test < dot_best) { + /* Check dot first to save on expensive angle-comparison. + * ideal case is 90d difference == 0.0 dot */ + dot_test = fabsf(dot_v3v3(e_dir, l->f->no)); + if (dot_test < dot_best) { - /* check we're in the correct corner (works with convex loops too) */ - if (angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, v_other->co, l->f->no) < - angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, l->next->v->co, l->f->no)) - { - dot_best = dot_test; - l_best = l; + /* check we're in the correct corner (works with convex loops too) */ + if (angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, v_other->co, l->f->no) < + angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, l->next->v->co, l->f->no)) + { + dot_best = dot_test; + l_best = l; + } } } } - } - if (l_best) { - BM_elem_index_set(e, BM_elem_index_get(l_best->f)); /* set_dirty */ + if (l_best) { + BM_elem_index_set(e, BM_elem_index_get(l_best->f)); /* set_dirty */ + } } } } - } - { - BMFace *f; - BLI_buffer_declare_static(BMEdge **, edge_net_temp_buf, 0, 128); + { + BMFace *f; + BLI_buffer_declare_static(BMEdge **, edge_net_temp_buf, 0, 128); - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, hflag)) { - bm_face_split_by_edges(bm, f, hflag, &edge_net_temp_buf); + BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, hflag)) { + bm_face_split_by_edges(bm, f, hflag, &edge_net_temp_buf); + } } + BLI_buffer_free(&edge_net_temp_buf); } - BLI_buffer_free(&edge_net_temp_buf); - } #ifdef USE_NET_ISLAND_CONNECT - /* before overwriting edge index values, collect edges left untouched */ - BLI_Stack *edges_loose = BLI_stack_new(sizeof(BMEdge * ), __func__); - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { - BLI_stack_push(edges_loose, &e); + /* before overwriting edge index values, collect edges left untouched */ + BLI_Stack *edges_loose = BLI_stack_new(sizeof(BMEdge *), __func__); + BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { + BLI_stack_push(edges_loose, &e); + } } - } #endif - EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); #ifdef USE_NET_ISLAND_CONNECT - /* we may have remaining isolated regions remaining, - * these will need to have connecting edges created */ - if (!BLI_stack_is_empty(edges_loose)) { - GHash *face_edge_map = BLI_ghash_ptr_new(__func__); + /* we may have remaining isolated regions remaining, + * these will need to have connecting edges created */ + if (!BLI_stack_is_empty(edges_loose)) { + GHash *face_edge_map = BLI_ghash_ptr_new(__func__); - MemArena *mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + MemArena *mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - BM_mesh_elem_index_ensure(bm, BM_FACE); + BM_mesh_elem_index_ensure(bm, BM_FACE); - { - BMBVHTree *bmbvh = BKE_bmbvh_new(bm, em->looptris, em->tottri, BMBVH_RESPECT_SELECT, NULL, false); + { + BMBVHTree *bmbvh = BKE_bmbvh_new(bm, em->looptris, em->tottri, BMBVH_RESPECT_SELECT, NULL, false); - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - BM_elem_index_set(e, -1); /* set_dirty */ - } + BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_index_set(e, -1); /* set_dirty */ + } - while (!BLI_stack_is_empty(edges_loose)) { - BLI_stack_pop(edges_loose, &e); - float e_center[3]; - mid_v3_v3v3(e_center, e->v1->co, e->v2->co); + while (!BLI_stack_is_empty(edges_loose)) { + BLI_stack_pop(edges_loose, &e); + float e_center[3]; + mid_v3_v3v3(e_center, e->v1->co, e->v2->co); - BMFace *f = BKE_bmbvh_find_face_closest(bmbvh, e_center, FLT_MAX); - if (f) { - ghash_insert_face_edge_link(face_edge_map, f, e, mem_arena); - BM_elem_index_set(e, BM_elem_index_get(f)); /* set_dirty */ + BMFace *f = BKE_bmbvh_find_face_closest(bmbvh, e_center, FLT_MAX); + if (f) { + ghash_insert_face_edge_link(face_edge_map, f, e, mem_arena); + BM_elem_index_set(e, BM_elem_index_get(f)); /* set_dirty */ + } } - } - BKE_bmbvh_free(bmbvh); - } + BKE_bmbvh_free(bmbvh); + } - bm->elem_index_dirty |= BM_EDGE; + bm->elem_index_dirty |= BM_EDGE; - BM_mesh_elem_table_ensure(bm, BM_FACE); + BM_mesh_elem_table_ensure(bm, BM_FACE); - /* detect edges chains that span faces - * and splice vertices into the closest edges */ - { - GHashIterator gh_iter; - - GHASH_ITER(gh_iter, face_edge_map) { - BMFace *f = BLI_ghashIterator_getKey(&gh_iter); - struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); - LinkNode *e_link = e_ls_base->list; - - do { - e = e_link->link; - - for (int j = 0; j < 2; j++) { - BMVert *v_pivot = (&e->v1)[j]; - /* checking that \a v_pivot isn't in the face - * prevents attempting to splice the same vertex into an edge from multiple faces */ - if (!BM_vert_in_face(v_pivot, f)) { - float v_pivot_co[3]; - float v_pivot_fac; - BMEdge *e_split = bm_face_split_edge_find( - e, f, v_pivot, bm->ftable, bm->totface, - v_pivot_co, &v_pivot_fac); - - if (e_split) { - /* for degenerate cases this vertex may be in one of this edges radial faces */ - if (!bm_vert_in_faces_radial(v_pivot, e_split, f)) { - BMEdge *e_new; - BMVert *v_new = BM_edge_split(bm, e_split, e_split->v1, &e_new, v_pivot_fac); - if (v_new) { - /* we _know_ these don't share an edge */ - BM_vert_splice(bm, v_pivot, v_new); - BM_elem_index_set(e_new, BM_elem_index_get(e_split)); + /* detect edges chains that span faces + * and splice vertices into the closest edges */ + { + GHashIterator gh_iter; + + GHASH_ITER(gh_iter, face_edge_map) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); + LinkNode *e_link = e_ls_base->list; + + do { + e = e_link->link; + + for (int j = 0; j < 2; j++) { + BMVert *v_pivot = (&e->v1)[j]; + /* checking that \a v_pivot isn't in the face + * prevents attempting to splice the same vertex into an edge from multiple faces */ + if (!BM_vert_in_face(v_pivot, f)) { + float v_pivot_co[3]; + float v_pivot_fac; + BMEdge *e_split = bm_face_split_edge_find( + e, f, v_pivot, bm->ftable, bm->totface, + v_pivot_co, &v_pivot_fac); + + if (e_split) { + /* for degenerate cases this vertex may be in one of this edges radial faces */ + if (!bm_vert_in_faces_radial(v_pivot, e_split, f)) { + BMEdge *e_new; + BMVert *v_new = BM_edge_split(bm, e_split, e_split->v1, &e_new, v_pivot_fac); + if (v_new) { + /* we _know_ these don't share an edge */ + BM_vert_splice(bm, v_pivot, v_new); + BM_elem_index_set(e_new, BM_elem_index_get(e_split)); + } } } } } - } - } while ((e_link = e_link->next)); + } while ((e_link = e_link->next)); + } } - } - { - MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + { + MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - GHashIterator gh_iter; + GHashIterator gh_iter; - GHASH_ITER(gh_iter, face_edge_map) { - BMFace *f = BLI_ghashIterator_getKey(&gh_iter); - struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); + GHASH_ITER(gh_iter, face_edge_map) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); - bm_face_split_by_edges_island_connect( - bm, f, - e_ls_base->list, e_ls_base->list_len, - mem_arena_edgenet); + bm_face_split_by_edges_island_connect( + bm, f, + e_ls_base->list, e_ls_base->list_len, + mem_arena_edgenet); - BLI_memarena_clear(mem_arena_edgenet); - } + BLI_memarena_clear(mem_arena_edgenet); + } - BLI_memarena_free(mem_arena_edgenet); - } + BLI_memarena_free(mem_arena_edgenet); + } - BLI_memarena_free(mem_arena); + BLI_memarena_free(mem_arena); - BLI_ghash_free(face_edge_map, NULL, NULL); + BLI_ghash_free(face_edge_map, NULL, NULL); - EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); - } + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + } - BLI_stack_free(edges_loose); + BLI_stack_free(edges_loose); #endif /* USE_NET_ISLAND_CONNECT */ + } + MEM_freeN(objects); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 0066afca540..41a0fa9ce38 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -3885,59 +3885,70 @@ void MESH_OT_edges_select_sharp(wmOperatorType *ot) static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - BLI_LINKSTACK_DECLARE(stack, BMFace *); - - BMIter iter, liter, liter2; - BMFace *f; - BMLoop *l, *l2; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness")); - BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - - BLI_LINKSTACK_INIT(stack); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) || - (BM_elem_flag_test(f, BM_ELEM_TAG) != 0) || - (BM_elem_flag_test(f, BM_ELEM_SELECT) == 0)) - { + if (bm->totfacesel == 0) { continue; } - BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0); + BLI_LINKSTACK_DECLARE(stack, BMFace *); - do { - BM_face_select_set(bm, f, true); + BMIter iter, liter, liter2; + BMFace *f; + BMLoop *l, *l2; - BM_elem_flag_enable(f, BM_ELEM_TAG); + BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) { - float angle_cos; + BLI_LINKSTACK_INIT(stack); - if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || - BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN)) - { - continue; - } + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) || + (BM_elem_flag_test(f, BM_ELEM_TAG) != 0) || + (BM_elem_flag_test(f, BM_ELEM_SELECT) == 0)) + { + continue; + } + + BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0); - angle_cos = dot_v3v3(f->no, l2->f->no); + do { + BM_face_select_set(bm, f, true); + + BM_elem_flag_enable(f, BM_ELEM_TAG); + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) { + float angle_cos; + + if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || + BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN)) + { + continue; + } - if (angle_cos > angle_limit_cos) { - BLI_LINKSTACK_PUSH(stack, l2->f); + angle_cos = dot_v3v3(f->no, l2->f->no); + + if (angle_cos > angle_limit_cos) { + BLI_LINKSTACK_PUSH(stack, l2->f); + } } } - } - } while ((f = BLI_LINKSTACK_POP(stack))); - } + } while ((f = BLI_LINKSTACK_POP(stack))); + } - BLI_LINKSTACK_FREE(stack); + BLI_LINKSTACK_FREE(stack); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index e8f3e592715..ab44e017fc6 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1030,7 +1030,7 @@ void EDBM_verts_mirror_cache_begin_ex( BM_mesh_elem_index_ensure(bm, BM_VERT); if (use_topology) { - ED_mesh_mirrtopo_init(me, NULL, &mesh_topo_store, true); + ED_mesh_mirrtopo_init__real_mesh(me, NULL, &mesh_topo_store, true); } else { tree = BLI_kdtree_new(bm->totvert); diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c index 22bfd8eedea..4c078d2ac8b 100644 --- a/source/blender/editors/mesh/mesh_mirror.c +++ b/source/blender/editors/mesh/mesh_mirror.c @@ -37,6 +37,8 @@ #include "BKE_DerivedMesh.h" #include "BLI_kdtree.h" #include "BKE_editmesh.h" +#include "BKE_library.h" +#include "BKE_mesh.h" #include "ED_mesh.h" @@ -93,7 +95,73 @@ int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, co else { MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert; int i; - + + for (i = 0; i < totvert; i++, mvert++) { + BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co); + } + } + + BLI_kdtree_balance(MirrKdStore.tree); + } + else if (mode == 'e') { /* end table */ + if (MirrKdStore.tree) { + BLI_kdtree_free(MirrKdStore.tree); + MirrKdStore.tree = NULL; + } + } + else { + BLI_assert(0); + } + + return 0; +} + +/* mode is 's' start, or 'e' end, or 'u' use */ +/* if end, ob can be NULL */ +int ED_mesh_mirror_spatial_table__real_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, const float co[3], char mode) +{ + if (mode == 'u') { /* use table */ + if (MirrKdStore.tree == NULL) + ED_mesh_mirror_spatial_table__real_mesh(ob, em, mesh, NULL, 's'); + + if (MirrKdStore.tree) { + KDTreeNearest nearest; + const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest); + + if (i != -1) { + if (nearest.dist < KD_THRESH) { + return i; + } + } + } + return -1; + } + else if (mode == 's') { /* start table */ + Mesh *me = ob->data; + const bool use_em = (!mesh && em && me->edit_btmesh == em); + const int totvert = use_em ? em->bm->totvert : mesh ? mesh->totvert : me->totvert; + + if (MirrKdStore.tree) /* happens when entering this call without ending it */ + ED_mesh_mirror_spatial_table__real_mesh(ob, em, mesh, co, 'e'); + + MirrKdStore.tree = BLI_kdtree_new(totvert); + + if (use_em) { + BMVert *eve; + BMIter iter; + int i; + + /* this needs to be valid for index lookups later (callers need) */ + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + + BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + BLI_kdtree_insert(MirrKdStore.tree, i, eve->co); + } + } + else { + MVert *mvert = mesh ? mesh->mvert : me->mvert; + int i; + for (i = 0; i < totvert; i++, mvert++) { BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co); } @@ -172,11 +240,62 @@ bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, MirrTopoStore_t *m } } +bool ED_mesh_mirrtopo_recalc_check__real_mesh(Mesh *me, Mesh *dm, MirrTopoStore_t *mesh_topo_store) +{ + const bool is_editmode = (me->edit_btmesh != NULL); + int totvert; + int totedge; + + if (dm) { + totvert = dm->totvert; + totedge = dm->totedge; + } + else if (me->edit_btmesh) { + totvert = me->edit_btmesh->bm->totvert; + totedge = me->edit_btmesh->bm->totedge; + } + else { + totvert = me->totvert; + totedge = me->totedge; + } + + if ((mesh_topo_store->index_lookup == NULL) || + (mesh_topo_store->prev_is_editmode != is_editmode) || + (totvert != mesh_topo_store->prev_vert_tot) || + (totedge != mesh_topo_store->prev_edge_tot)) + { + return true; + } + else { + return false; + } + +} + void ED_mesh_mirrtopo_init( Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store, const bool skip_em_vert_array_init) { + Mesh *fake_mesh = NULL; + + if (dm != NULL) { + /* ED_real_mesh_mirrtopo_init() only uses the counts, not the actual data */ + fake_mesh = BKE_mesh_new_nomain(dm->getNumVerts(dm), dm->getNumEdges(dm), dm->getNumTessFaces(dm), + dm->getNumLoops(dm), dm->getNumPolys(dm)); + } + + ED_mesh_mirrtopo_init__real_mesh(me, fake_mesh, mesh_topo_store, skip_em_vert_array_init); + + if (dm != NULL) { + BKE_id_free(NULL, fake_mesh); + } +} + +void ED_mesh_mirrtopo_init__real_mesh( + Mesh *me, Mesh *dm, MirrTopoStore_t *mesh_topo_store, + const bool skip_em_vert_array_init) +{ const bool is_editmode = (me->edit_btmesh != NULL); MEdge *medge = NULL, *med; BMEditMesh *em = dm ? NULL : me->edit_btmesh; @@ -208,7 +327,7 @@ void ED_mesh_mirrtopo_init( totvert = em->bm->totvert; } else { - totvert = dm ? dm->getNumVerts(dm) : me->totvert; + totvert = dm ? dm->totvert : me->totvert; } topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr"); @@ -224,8 +343,8 @@ void ED_mesh_mirrtopo_init( } } else { - totedge = dm ? dm->getNumEdges(dm) : me->totedge; - medge = dm ? dm->getEdgeArray(dm) : me->medge; + totedge = dm ? dm->totedge : me->totedge; + medge = dm ? dm->medge : me->medge; for (a = 0, med = medge; a < totedge; a++, med++) { const unsigned int i1 = med->v1, i2 = med->v2; diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 83458127820..9b86f904161 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -707,6 +707,30 @@ int ED_mesh_mirror_topo_table( return 0; } +/* mode is 's' start, or 'e' end, or 'u' use */ +/* if end, ob can be NULL */ +/* note, is supposed return -1 on error, which callers are currently checking for, but is not used so far */ +int ED_mesh_mirror_topo_table__real_mesh( + Object *ob, Mesh *mesh, char mode) +{ + if (mode == 'u') { /* use table */ + if (ED_mesh_mirrtopo_recalc_check__real_mesh(ob->data, mesh, &mesh_topo_store)) { + ED_mesh_mirror_topo_table__real_mesh(ob, mesh, 's'); + } + } + else if (mode == 's') { /* start table */ + ED_mesh_mirrtopo_init__real_mesh(ob->data, mesh, &mesh_topo_store, false); + } + else if (mode == 'e') { /* end table */ + ED_mesh_mirrtopo_free(&mesh_topo_store); + } + else { + BLI_assert(0); + } + + return 0; +} + /** \} */ @@ -742,6 +766,38 @@ int mesh_get_x_mirror_vert(Object *ob, DerivedMesh *dm, int index, const bool us } } +static int mesh_get_x_mirror_vert_spatial__real_mesh(Object *ob, Mesh *mesh, int index) +{ + Mesh *me = ob->data; + MVert *mvert = mesh ? mesh->mvert : me->mvert; + float vec[3]; + + mvert = &mvert[index]; + vec[0] = -mvert->co[0]; + vec[1] = mvert->co[1]; + vec[2] = mvert->co[2]; + + return ED_mesh_mirror_spatial_table__real_mesh(ob, NULL, mesh, vec, 'u'); +} + +static int mesh_get_x_mirror_vert_topo__real_mesh(Object *ob, Mesh *mesh, int index) +{ + if (ED_mesh_mirror_topo_table__real_mesh(ob, mesh, 'u') == -1) + return -1; + + return mesh_topo_store.index_lookup[index]; +} + +int mesh_get_x_mirror_vert__real_mesh(Object *ob, Mesh *mesh, int index, const bool use_topology) +{ + if (use_topology) { + return mesh_get_x_mirror_vert_topo__real_mesh(ob, mesh, index); + } + else { + return mesh_get_x_mirror_vert_spatial__real_mesh(ob, mesh, index); + } +} + static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, const float co[3]) { float vec[3]; @@ -991,7 +1047,67 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, DerivedMesh *dm) BLI_ghash_free(fhash, NULL, NULL); MEM_freeN(mirrorverts); - + + return mirrorfaces; +} + +/* This is a Mesh-based copy of mesh_get_x_mirror_faces() */ +int *mesh_get_x_mirror_faces__real_mesh(Object *ob, BMEditMesh *em, Mesh *mesh) +{ + Mesh *me = ob->data; + MVert *mv, *mvert; + MFace mirrormf, *mf, *hashmf, *mface; + GHash *fhash; + int *mirrorverts, *mirrorfaces; + + BLI_assert(em == NULL); /* Does not work otherwise, currently... */ + + const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + const int totvert = mesh ? mesh->totvert : me->totvert; + const int totface = mesh ? mesh->totface : me->totface; + int a; + + mirrorverts = MEM_callocN(sizeof(int) * totvert, "MirrorVerts"); + mirrorfaces = MEM_callocN(sizeof(int) * 2 * totface, "MirrorFaces"); + + mvert = mesh ? mesh->mvert : me->mvert; + mface = mesh ? mesh->mface : me->mface; + + ED_mesh_mirror_spatial_table__real_mesh(ob, em, mesh, NULL, 's'); + + for (a = 0, mv = mvert; a < totvert; a++, mv++) + mirrorverts[a] = mesh_get_x_mirror_vert__real_mesh(ob, mesh, a, use_topology); + + ED_mesh_mirror_spatial_table__real_mesh(ob, em, mesh, NULL, 'e'); + + fhash = BLI_ghash_new_ex(mirror_facehash, mirror_facecmp, "mirror_facehash gh", me->totface); + for (a = 0, mf = mface; a < totface; a++, mf++) + BLI_ghash_insert(fhash, mf, mf); + + for (a = 0, mf = mface; a < totface; a++, mf++) { + mirrormf.v1 = mirrorverts[mf->v3]; + mirrormf.v2 = mirrorverts[mf->v2]; + mirrormf.v3 = mirrorverts[mf->v1]; + mirrormf.v4 = (mf->v4) ? mirrorverts[mf->v4] : 0; + + /* make sure v4 is not 0 if a quad */ + if (mf->v4 && mirrormf.v4 == 0) { + SWAP(unsigned int, mirrormf.v1, mirrormf.v3); + SWAP(unsigned int, mirrormf.v2, mirrormf.v4); + } + + hashmf = BLI_ghash_lookup(fhash, &mirrormf); + if (hashmf) { + mirrorfaces[a * 2] = hashmf - mface; + mirrorfaces[a * 2 + 1] = mirror_facerotation(&mirrormf, hashmf); + } + else + mirrorfaces[a * 2] = -1; + } + + BLI_ghash_free(fhash, NULL, NULL); + MEM_freeN(mirrorverts); + return mirrorfaces; } diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index eb0492daf9c..6f8b50bb68a 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1629,9 +1629,17 @@ static void move_to_collection_menus_free(MoveToCollectionData **menu) static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout, void *menu_v) { MoveToCollectionData *menu = menu_v; + const char *name; + + if (menu->collection->flag & COLLECTION_IS_MASTER) { + name = IFACE_("Scene Collection"); + } + else { + name = menu->collection->id.name + 2; + } uiItemIntO(layout, - menu->collection->id.name + 2, + name, ICON_NONE, menu->ot->idname, "collection_index", diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 6a73e1912ab..3ac7a14753b 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2287,8 +2287,6 @@ static int make_override_static_exec(bContext *C, wmOperator *op) bool success = false; if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) { - // TODO: support making the group itself override and putting - // it directly into the scene collections const ListBase dup_collection_objects = BKE_collection_object_cache_get(obact->dup_group); Base *base = BLI_findlink(&dup_collection_objects, RNA_enum_get(op->ptr, "object")); Object *obcollection = obact; @@ -2305,6 +2303,19 @@ static int make_override_static_exec(bContext *C, wmOperator *op) } FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + /* Then, we make static override of the whole set of objects in the collection. */ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, ob) + { + if (ob->type == OB_ARMATURE && ob->pose != NULL) { + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) { + if (pchan->custom != NULL) { + pchan->custom->id.tag &= ~ LIB_TAG_DOIT; + } + } + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + success = BKE_override_static_create_from_tag(bmain); /* Intantiate our newly overridden objects in scene, if not yet done. */ @@ -2313,7 +2324,10 @@ static int make_override_static_exec(bContext *C, wmOperator *op) Collection *new_collection = (Collection *)collection->id.newid; FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(new_collection, new_ob) { - if (new_ob != NULL && (base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) { + if (new_ob != NULL && + new_ob->id.override_static != NULL && + (base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) + { BKE_collection_object_add_from(bmain, scene, obcollection, new_ob); DEG_id_tag_update_ex(bmain, &new_ob->id, OB_RECALC_OB | DEG_TAG_BASE_FLAGS_UPDATE); /* parent to 'collection' empty */ diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 3df934a8dca..e0427b4797c 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -55,6 +55,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_object.h" +#include "BKE_library.h" #include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_particle.h" @@ -364,7 +365,7 @@ typedef struct PEData { Scene *scene; ViewLayer *view_layer; Object *ob; - DerivedMesh *dm; + Mesh *mesh; PTCacheEdit *edit; BVHTreeFromMesh shape_bvh; Depsgraph *depsgraph; @@ -426,15 +427,15 @@ static void PE_set_view3d_data(bContext *C, PEData *data) static bool PE_create_shape_tree(PEData *data, Object *shapeob) { - DerivedMesh *dm = shapeob->derivedFinal; + Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_object(shapeob, 0); memset(&data->shape_bvh, 0, sizeof(data->shape_bvh)); - if (!dm) { + if (!mesh) { return false; } - return (bvhtree_from_mesh_get(&data->shape_bvh, dm, BVHTREE_FROM_LOOPTRI, 4) != NULL); + return (BKE_bvhtree_from_mesh_get(&data->shape_bvh, mesh, BVHTREE_FROM_LOOPTRI, 4) != NULL); } static void PE_free_shape_tree(PEData *data) @@ -641,9 +642,11 @@ static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selecte static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected) { + Object *ob_eval = DEG_get_evaluated_object(data->depsgraph, data->ob); PTCacheEdit *edit = data->edit; ParticleSystem *psys = edit->psys; ParticleSystemModifierData *psmd = NULL; + ParticleSystemModifierData *psmd_eval = NULL; ParticleEditSettings *pset= PE_settings(data->scene); POINT_P; KEY_K; float mat[4][4], imat[4][4]; @@ -654,6 +657,10 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected if (edit->psys) psmd= psys_get_modifier(data->ob, edit->psys); + if (psmd != NULL) { + psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name); + } + /* all is selected in path mode */ if (pset->selectmode==SCE_SELECT_PATH) selected= 0; @@ -667,7 +674,7 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected if (selected==0 || key->flag & PEK_SELECT) { if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) { if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) { - psys_mat_hair_to_global(data->ob, psmd->dm_final, psys->part->from, psys->particles + p, mat); + psys_mat_hair_to_global(data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat); invert_m4_m4(imat, mat); } @@ -682,7 +689,7 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected if (selected==0 || key->flag & PEK_SELECT) { if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) { if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) { - psys_mat_hair_to_global(data->ob, psmd->dm_final, psys->part->from, psys->particles + p, mat); + psys_mat_hair_to_global(data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat); invert_m4_m4(imat, mat); } @@ -769,7 +776,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys) psmd= psys_get_modifier(ob, psys); totpart= psys->totpart; - if (!psmd->dm_final) + if (!psmd->mesh_final) return; tree= BLI_kdtree_new(totpart); @@ -777,7 +784,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys) /* insert particles into kd tree */ LOOP_PARTICLES { key = pa->hair; - psys_mat_hair_to_orco(ob, psmd->dm_final, psys->part->from, pa, mat); + psys_mat_hair_to_orco(ob, psmd->mesh_final, psys->part->from, pa, mat); copy_v3_v3(co, key->co); mul_m4_v3(mat, co); BLI_kdtree_insert(tree, p, co); @@ -791,7 +798,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys) LOOP_PARTICLES { key = pa->hair; - psys_mat_hair_to_orco(ob, psmd->dm_final, psys->part->from, pa, mat); + psys_mat_hair_to_orco(ob, psmd->mesh_final, psys->part->from, pa, mat); copy_v3_v3(co, key->co); mul_m4_v3(mat, co); co[0] = -co[0]; @@ -817,7 +824,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys) BLI_kdtree_free(tree); } -static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa) +static void PE_mirror_particle(Object *ob, Mesh *mesh, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa) { HairKey *hkey, *mhkey; PTCacheEditPoint *point, *mpoint; @@ -868,8 +875,8 @@ static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys } /* mirror positions and tags */ - psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat); - psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat); + psys_mat_hair_to_orco(ob, mesh, psys->part->from, pa, mat); + psys_mat_hair_to_orco(ob, mesh, psys->part->from, mpa, mmat); invert_m4_m4(immat, mmat); hkey=pa->hair; @@ -906,7 +913,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys) edit= psys->edit; psmd= psys_get_modifier(ob, psys); - if (!psmd->dm_final) + if (!psmd->mesh_final) return; if (!edit->mirror_cache) @@ -919,7 +926,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys) * to avoid doing mirror twice */ LOOP_POINTS { if (point->flag & PEP_EDIT_RECALC) { - PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL); + PE_mirror_particle(ob, psmd->mesh_final, psys, psys->particles + p, NULL); if (edit->mirror_cache[p] != -1) edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC; @@ -954,11 +961,11 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit) psys = edit->psys; psmd = psys_get_modifier(ob, psys); - if (!psmd->dm_final) + if (!psmd->mesh_final) return; LOOP_EDITED_POINTS { - psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles + p, hairmat); + psys_mat_hair_to_object(ob, psmd->mesh_final, psys->part->from, psys->particles + p, hairmat); LOOP_KEYS { mul_m4_v3(hairmat, key->co); @@ -1105,12 +1112,12 @@ void recalc_emitter_field(Depsgraph *depsgraph, Object *ob, ParticleSystem *psys { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys); - DerivedMesh *dm = psys_get_modifier(object_eval, psys_eval)->dm_final; + Mesh *mesh = psys_get_modifier(object_eval, psys_eval)->mesh_final; PTCacheEdit *edit = psys->edit; float *vec, *nor; int i, totface /*, totvert*/; - if (!dm) + if (!mesh) return; if (edit->emitter_cosnos) @@ -1118,7 +1125,7 @@ void recalc_emitter_field(Depsgraph *depsgraph, Object *ob, ParticleSystem *psys BLI_kdtree_free(edit->emitter_field); - totface=dm->getNumTessFaces(dm); + totface = mesh->totface; /*totvert=dm->getNumVerts(dm);*/ /*UNSUED*/ edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float), "emitter cosnos"); @@ -1129,23 +1136,23 @@ void recalc_emitter_field(Depsgraph *depsgraph, Object *ob, ParticleSystem *psys nor=vec+3; for (i=0; i<totface; i++, vec+=6, nor+=6) { - MFace *mface=dm->getTessFaceData(dm, i, CD_MFACE); + MFace *mface = &mesh->mface[i]; MVert *mvert; - mvert=dm->getVertData(dm, mface->v1, CD_MVERT); + mvert = &mesh->mvert[mface->v1]; copy_v3_v3(vec, mvert->co); VECCOPY(nor, mvert->no); - mvert=dm->getVertData(dm, mface->v2, CD_MVERT); + mvert = &mesh->mvert[mface->v2]; add_v3_v3v3(vec, vec, mvert->co); VECADD(nor, nor, mvert->no); - mvert=dm->getVertData(dm, mface->v3, CD_MVERT); + mvert = &mesh->mvert[mface->v3]; add_v3_v3v3(vec, vec, mvert->co); VECADD(nor, nor, mvert->no); if (mface->v4) { - mvert=dm->getVertData(dm, mface->v4, CD_MVERT); + mvert = &mesh->mvert[mface->v4]; add_v3_v3v3(vec, vec, mvert->co); VECADD(nor, nor, mvert->no); @@ -1208,12 +1215,12 @@ void update_world_cos(Depsgraph *depsgraph, Object *ob, PTCacheEdit *edit) psys_eval = psmd_eval->psys; } - if (psys == 0 || psys->edit == 0 || psmd_eval->dm_final == NULL) + if (psys == 0 || psys->edit == 0 || psmd_eval->mesh_final == NULL) return; LOOP_POINTS { if (!(psys->flag & PSYS_GLOBAL_HAIR)) - psys_mat_hair_to_global(ob_eval, psmd_eval->dm_final, psys->part->from, psys_eval->particles+p, hairmat); + psys_mat_hair_to_global(ob_eval, psmd_eval->mesh_final, psys->part->from, psys_eval->particles+p, hairmat); LOOP_KEYS { copy_v3_v3(key->world_co, key->co); @@ -1860,7 +1867,7 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool LOOP_VISIBLE_POINTS { if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR)) - psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + p, mat); + psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, psys->particles + p, mat); if (pset->selectmode==SCE_SELECT_POINT) { LOOP_KEYS { @@ -2305,7 +2312,7 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror) psmd= psys_get_modifier(ob, psys); LOOP_TAGGED_POINTS { - PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL); + PE_mirror_particle(ob, psmd->mesh_final, psys, psys->particles + p, NULL); } } @@ -2385,7 +2392,7 @@ static void remove_tagged_keys(Object *ob, ParticleSystem *psys) LOOP_POINTS { LOOP_TAGGED_KEYS { - PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL); + PE_mirror_particle(ob, psmd->mesh_final, psys, psys->particles + p, NULL); break; } } @@ -2600,7 +2607,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) /* insert particles into kd tree */ LOOP_SELECTED_POINTS { - psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles+p, mat); + psys_mat_hair_to_object(ob, psmd->mesh_final, psys->part->from, psys->particles+p, mat); copy_v3_v3(co, point->keys->co); mul_m4_v3(mat, co); BLI_kdtree_insert(tree, p, co); @@ -2610,7 +2617,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) /* tag particles to be removed */ LOOP_SELECTED_POINTS { - psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles+p, mat); + psys_mat_hair_to_object(ob, psmd->mesh_final, psys->part->from, psys->particles+p, mat); copy_v3_v3(co, point->keys->co); mul_m4_v3(mat, co); @@ -2845,17 +2852,17 @@ static void PE_mirror_x( return; psmd= psys_get_modifier(ob, psys); - if (!psmd->dm_final) + if (!psmd->mesh_final) return; - const bool use_dm_final_indices = (psys->part->use_modifier_stack && !psmd->dm_final->deformedOnly); + const bool use_dm_final_indices = (psys->part->use_modifier_stack && !psmd->mesh_final->runtime.deformed_only); /* NOTE: this is not nice to use tessfaces but hard to avoid since pa->num uses tessfaces */ BKE_mesh_tessface_ensure(me); - /* Note: In case psys uses DM tessface indices, we mirror final DM itself, not orig mesh. Avoids an (impossible) - * dm -> orig -> dm tessface indices conversion... */ - mirrorfaces = mesh_get_x_mirror_faces(ob, NULL, use_dm_final_indices ? psmd->dm_final : NULL); + /* Note: In case psys uses Mesh tessface indices, we mirror final Mesh itself, not orig mesh. Avoids an (impossible) + * mesh -> orig -> mesh tessface indices conversion... */ + mirrorfaces = mesh_get_x_mirror_faces__real_mesh(ob, NULL, use_dm_final_indices ? psmd->mesh_final : NULL); if (!edit->mirror_cache) PE_update_mirror_cache(ob, psys); @@ -2869,7 +2876,7 @@ static void PE_mirror_x( if (point_is_selected(point)) { if (edit->mirror_cache[p] != -1) { /* already has a mirror, don't need to duplicate */ - PE_mirror_particle(ob, psmd->dm_final, psys, pa, NULL); + PE_mirror_particle(ob, psmd->mesh_final, psys, pa, NULL); continue; } else @@ -2882,7 +2889,7 @@ static void PE_mirror_x( } if (newtotpart != psys->totpart) { - MFace *mtessface = use_dm_final_indices ? psmd->dm_final->getTessFaceArray(psmd->dm_final) : me->mface; + MFace *mtessface = use_dm_final_indices ? psmd->mesh_final->mface : me->mface; /* allocate new arrays and copy existing */ new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new"); @@ -2951,7 +2958,7 @@ static void PE_mirror_x( } else { newpa->num_dmcache = psys_particle_dm_face_lookup( - psmd->dm_final, psmd->dm_deformed, newpa->num, newpa->fuv, NULL); + psmd->mesh_final, psmd->mesh_deformed, newpa->num, newpa->fuv, NULL); } /* update edit key pointers */ @@ -2962,7 +2969,7 @@ static void PE_mirror_x( } /* map key positions as mirror over x axis */ - PE_mirror_particle(ob, psmd->dm_final, psys, pa, newpa); + PE_mirror_particle(ob, psmd->mesh_final, psys, pa, newpa); newpa++; newpoint++; @@ -3172,7 +3179,7 @@ static void brush_puff(PEData *data, int point_index) } if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) { - psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat); + psys_mat_hair_to_global(data->ob, data->mesh, psys->part->from, psys->particles + point_index, mat); invert_m4_m4(imat, mat); } else { @@ -3367,7 +3374,7 @@ static void intersect_dm_quad_weights(const float v1[3], const float v2[3], cons } /* check intersection with a derivedmesh */ -static int particle_intersect_dm(const bContext *C, Scene *scene, Object *ob, DerivedMesh *dm, +static int particle_intersect_mesh(const bContext *C, Scene *scene, Object *ob, Mesh *mesh, float *vert_cos, const float co1[3], const float co2[3], float *min_d, int *min_face, float *min_w, @@ -3381,10 +3388,11 @@ static int particle_intersect_dm(const bContext *C, Scene *scene, Object *ob, De float cur_d, cur_uv[2], v1[3], v2[3], v3[3], v4[3], min[3], max[3], p_min[3], p_max[3]; float cur_ipoint[3]; - if (dm == NULL) { + if (mesh == NULL) { psys_disable_all(ob); - dm = mesh_get_derived_final(depsgraph, scene, ob, 0); + /* TODO(Sybren): port to Mesh when we have decided how to handle derivedFinal and derivedDeform */ + DerivedMesh *dm = mesh_get_derived_final(depsgraph, scene, ob, 0); if (dm == NULL) dm = mesh_get_derived_deform(depsgraph, scene, ob, 0); @@ -3392,10 +3400,13 @@ static int particle_intersect_dm(const bContext *C, Scene *scene, Object *ob, De if (dm == NULL) return 0; + + mesh = BKE_id_new_nomain(ID_ME, NULL); + DM_to_mesh(dm, mesh, ob, CD_MASK_EVERYTHING, false); } /* BMESH_ONLY, deform dm may not have tessface */ - DM_ensure_tessface(dm); + BKE_mesh_tessface_ensure(mesh); if (pa_minmax==0) { @@ -3408,9 +3419,9 @@ static int particle_intersect_dm(const bContext *C, Scene *scene, Object *ob, De copy_v3_v3(p_max, pa_minmax+3); } - totface=dm->getNumTessFaces(dm); - mface=dm->getTessFaceDataArray(dm, CD_MFACE); - mvert=dm->getVertDataArray(dm, CD_MVERT); + totface = mesh->totface; + mface = mesh->mface; + mvert = mesh->mvert; /* lets intersect the faces */ for (i=0; i<totface; i++, mface++) { @@ -3504,7 +3515,7 @@ static int brush_add(const bContext *C, PEData *data, short number) Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene= data->scene; Object *ob= data->ob; - DerivedMesh *dm; + Mesh *mesh; PTCacheEdit *edit = data->edit; ParticleSystem *psys= edit->psys; ParticleData *add_pars; @@ -3537,13 +3548,13 @@ static int brush_add(const bContext *C, PEData *data, short number) timestep= psys_get_timestep(&sim); - if (psys->part->use_modifier_stack || psmd->dm_final->deformedOnly) { - dm = psmd->dm_final; + if (psys->part->use_modifier_stack || psmd->mesh_final->runtime.deformed_only) { + mesh = psmd->mesh_final; } else { - dm = psmd->dm_deformed; + mesh = psmd->mesh_deformed; } - BLI_assert(dm); + BLI_assert(mesh); for (i=0; i<number; i++) { if (number>1) { @@ -3570,16 +3581,16 @@ static int brush_add(const bContext *C, PEData *data, short number) min_d=2.0; /* warning, returns the derived mesh face */ - if (particle_intersect_dm(C, scene, ob, dm, 0, co1, co2, &min_d, &add_pars[n].num_dmcache, add_pars[n].fuv, 0, 0, 0, 0)) { - if (psys->part->use_modifier_stack && !psmd->dm_final->deformedOnly) { + if (particle_intersect_mesh(C, scene, ob, mesh, 0, co1, co2, &min_d, &add_pars[n].num_dmcache, add_pars[n].fuv, 0, 0, 0, 0)) { + if (psys->part->use_modifier_stack && !psmd->mesh_final->runtime.deformed_only) { add_pars[n].num = add_pars[n].num_dmcache; add_pars[n].num_dmcache = DMCACHE_ISCHILD; } - else if (dm == psmd->dm_deformed) { + else if (mesh == psmd->mesh_deformed) { /* Final DM is not same topology as orig mesh, we have to map num_dmcache to real final dm. */ add_pars[n].num = add_pars[n].num_dmcache; add_pars[n].num_dmcache = psys_particle_dm_face_lookup( - psmd->dm_final, psmd->dm_deformed, + psmd->mesh_final, psmd->mesh_deformed, add_pars[n].num, add_pars[n].fuv, NULL); } else { @@ -3621,7 +3632,7 @@ static int brush_add(const bContext *C, PEData *data, short number) tree=BLI_kdtree_new(psys->totpart); for (i=0, pa=psys->particles; i<totpart; i++, pa++) { - psys_particle_on_dm(psmd->dm_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, cur_co, 0, 0, 0, 0); + psys_particle_on_dm(psmd->mesh_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, cur_co, 0, 0, 0, 0); BLI_kdtree_insert(tree, i, cur_co); } @@ -3665,7 +3676,7 @@ static int brush_add(const bContext *C, PEData *data, short number) int w, maxw; float maxd, totw=0.0, weight[3]; - psys_particle_on_dm(psmd->dm_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co1, 0, 0, 0, 0); + psys_particle_on_dm(psmd->mesh_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co1, 0, 0, 0, 0); maxw = BLI_kdtree_find_nearest_n(tree, co1, ptn, 3); maxd= ptn[maxw-1].dist; @@ -3730,7 +3741,7 @@ static int brush_add(const bContext *C, PEData *data, short number) } } for (k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) { - psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat); + psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, pa, hairmat); invert_m4_m4(imat, hairmat); mul_m4_v3(imat, hkey->co); } @@ -3922,7 +3933,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) case PE_BRUSH_PUFF: { if (edit->psys) { - data.dm= psmd->dm_final; + data.mesh = psmd->mesh_final; data.mval= mval; data.rad= pe_brush_size_get(scene, brush); data.select= selected; @@ -3978,7 +3989,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) case PE_BRUSH_WEIGHT: { if (edit->psys) { - data.dm= psmd->dm_final; + data.mesh = psmd->mesh_final; data.mval= mval; data.rad= pe_brush_size_get(scene, brush); @@ -4325,7 +4336,7 @@ int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3]) LOOP_VISIBLE_POINTS { if (psys) - psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles+p, mat); + psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, psys->particles+p, mat); LOOP_SELECTED_KEYS { copy_v3_v3(co, key->co); @@ -4363,7 +4374,7 @@ void PE_create_particle_edit( } /* no psmd->dm happens in case particle system modifier is not enabled */ - if (!(psys && psmd_eval && psmd_eval->dm_final) && !cache) + if (!(psys && psmd_eval && psmd_eval->mesh_final) && !cache) return; if (cache && cache->flag & PTCACHE_DISK_CACHE) diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 79d52abb32d..cb7c90a6c3d 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -33,6 +33,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_scene_types.h" @@ -48,6 +49,7 @@ #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_particle.h" @@ -574,7 +576,7 @@ static void disconnect_hair( point++; } - psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat); + psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, pa, hairmat); for (k=0, key=pa->hair; k<pa->totkey; k++, key++) { mul_m4_v3(hairmat, key->co); @@ -653,13 +655,13 @@ static bool remap_hair_emitter( MFace *mface = NULL, *mf; MEdge *medge = NULL, *me; MVert *mvert; - DerivedMesh *dm, *target_dm; + Mesh *mesh, *target_mesh; int numverts; int i, k; float from_ob_imat[4][4], to_ob_imat[4][4]; float from_imat[4][4], to_imat[4][4]; - if (!target_psmd->dm_final) + if (!target_psmd->mesh_final) return false; if (!psys->part || psys->part->type != PART_HAIR) return false; @@ -673,40 +675,46 @@ static bool remap_hair_emitter( invert_m4_m4(from_imat, from_mat); invert_m4_m4(to_imat, to_mat); - if (target_psmd->dm_final->deformedOnly) { + if (target_psmd->mesh_final->runtime.deformed_only) { /* we don't want to mess up target_psmd->dm when converting to global coordinates below */ - dm = target_psmd->dm_final; + mesh = target_psmd->mesh_final; } else { - dm = target_psmd->dm_deformed; + mesh = target_psmd->mesh_deformed; } - target_dm = target_psmd->dm_final; - if (dm == NULL) { + target_mesh = target_psmd->mesh_final; + if (mesh == NULL) { return false; } /* don't modify the original vertices */ - dm = CDDM_copy(dm); + BKE_id_copy_ex( + NULL, &mesh->id, (ID **)&mesh, + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | + LIB_ID_COPY_NO_PREVIEW, + false); /* BMESH_ONLY, deform dm may not have tessface */ - DM_ensure_tessface(dm); + BKE_mesh_tessface_ensure(mesh); - numverts = dm->getNumVerts(dm); - mvert = dm->getVertArray(dm); + numverts = mesh->totvert; + mvert = mesh->mvert; /* convert to global coordinates */ for (i=0; i<numverts; i++) mul_m4_v3(to_mat, mvert[i].co); - if (dm->getNumTessFaces(dm) != 0) { - mface = dm->getTessFaceArray(dm); - bvhtree_from_mesh_get(&bvhtree, dm, BVHTREE_FROM_FACES, 2); + if (mesh->totface != 0) { + mface = mesh->mface; + BKE_bvhtree_from_mesh_get(&bvhtree, mesh, BVHTREE_FROM_FACES, 2); } - else if (dm->getNumEdges(dm) != 0) { - medge = dm->getEdgeArray(dm); - bvhtree_from_mesh_get(&bvhtree, dm, BVHTREE_FROM_EDGES, 2); + else if (mesh->totedge != 0) { + medge = mesh->medge; + BKE_bvhtree_from_mesh_get(&bvhtree, mesh, BVHTREE_FROM_EDGES, 2); } else { - dm->release(dm); + BKE_id_free(NULL, mesh); return false; } @@ -751,7 +759,7 @@ static bool remap_hair_emitter( tpa->foffset = 0.0f; tpa->num = nearest.index; - tpa->num_dmcache = psys_particle_dm_face_lookup(target_dm, dm, tpa->num, tpa->fuv, NULL); + tpa->num_dmcache = psys_particle_dm_face_lookup(target_mesh, mesh, tpa->num, tpa->fuv, NULL); } else { me = &medge[nearest.index]; @@ -777,7 +785,7 @@ static bool remap_hair_emitter( copy_m4_m4(imat, target_ob->obmat); else { /* note: using target_dm here, which is in target_ob object space and has full modifiers */ - psys_mat_hair_to_object(target_ob, target_dm, target_psys->part->from, tpa, hairmat); + psys_mat_hair_to_object(target_ob, target_mesh, target_psys->part->from, tpa, hairmat); invert_m4_m4(imat, hairmat); } mul_m4_m4m4(imat, imat, to_imat); @@ -823,7 +831,7 @@ static bool remap_hair_emitter( } free_bvhtree_from_mesh(&bvhtree); - dm->release(dm); + BKE_id_free(NULL, mesh); psys_free_path_cache(target_psys, target_edit); @@ -994,7 +1002,7 @@ static bool copy_particle_systems_to_object(const bContext *C, ModifierData *md; ParticleSystem *psys_start = NULL, *psys, *psys_from; ParticleSystem **tmp_psys; - DerivedMesh *final_dm; + Mesh *final_mesh; CustomDataMask cdmask; int i, totpsys; @@ -1036,8 +1044,11 @@ static bool copy_particle_systems_to_object(const bContext *C, psys_start = totpsys > 0 ? tmp_psys[0] : NULL; /* get the DM (psys and their modifiers have not been appended yet) */ - final_dm = mesh_get_derived_final(depsgraph, scene, ob_to, cdmask); - + /* TODO(Sybren): use mesh_evaluated instead */ + DerivedMesh *final_dm = mesh_get_derived_final(depsgraph, scene, ob_to, cdmask); + final_mesh = BKE_id_new_nomain(ID_ME, NULL); + DM_to_mesh(final_dm, final_mesh, ob_to, CD_MASK_EVERYTHING, false); + /* now append psys to the object and make modifiers */ for (i = 0, psys_from = PSYS_FROM_FIRST; i < totpsys; @@ -1060,10 +1071,17 @@ static bool copy_particle_systems_to_object(const bContext *C, modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd); psmd->psys = psys; - psmd->dm_final = CDDM_copy(final_dm); - CDDM_calc_normals(psmd->dm_final); - DM_ensure_tessface(psmd->dm_final); - + BKE_id_copy_ex( + NULL, &final_mesh->id, (ID **)&psmd->mesh_final, + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | + LIB_ID_COPY_NO_PREVIEW, + false); + + BKE_mesh_calc_normals(psmd->mesh_final); + BKE_mesh_tessface_ensure(psmd->mesh_final); + if (psys_from->edit) { copy_particle_edit(depsgraph, scene, ob_to, psys, psys_from); } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 8ebdb5f32b8..7167b48c06e 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -848,6 +848,7 @@ void ED_screens_initialize(wmWindowManager *wm) ED_screen_global_areas_create(win); } ED_screen_refresh(wm, win); + ED_screen_set_active_region(NULL, win, &win->eventstate->x); } } @@ -992,9 +993,8 @@ static void screen_cursor_set(wmWindow *win, const int xy[2]) /* called in wm_event_system.c. sets state vars in screen, cursors */ /* event type is mouse move */ -void ED_screen_set_active_region(bContext *C, const int xy[2]) +void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2]) { - wmWindow *win = CTX_wm_window(C); bScreen *scr = WM_window_get_active_screen(win); if (scr) { @@ -1058,7 +1058,9 @@ void ED_screen_set_active_region(bContext *C, const int xy[2]) /* this used to be a notifier, but needs to be done immediate * because it can undo setting the right button as active due * to delayed notifier handling */ - UI_screen_free_active_but(C, scr); + if (C) { + UI_screen_free_active_but(C, scr); + } } else region_cursor_set(win, false); diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index fd8fe84cffc..a1435d5916a 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -5761,7 +5761,7 @@ void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot) /* api callbacks */ ot->invoke = texture_paint_add_texture_paint_slot_invoke; ot->exec = texture_paint_add_texture_paint_slot_exec; - ot->poll = ED_operator_region_view3d_active; + ot->poll = ED_operator_object_active; /* flags */ ot->flag = OPTYPE_UNDO; diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index e0041d36a24..206cdd57342 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -65,7 +65,7 @@ bool outliner_is_collection_tree_element(const TreeElement *te) return false; } - if (tselem->type == TSE_LAYER_COLLECTION) { + if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { return true; } else if (tselem->type == 0 && te->idcode == ID_GR) { @@ -87,7 +87,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te) LayerCollection *lc = te->directdata; return lc->collection; } - else if (ELEM(tselem->type, TSE_R_LAYER, TSE_SCENE_COLLECTION_BASE)) { + else if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { Scene *scene = (Scene*)tselem->id; return BKE_collection_master(scene); } @@ -104,7 +104,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te) static int collections_editor_poll(bContext *C) { SpaceOops *so = CTX_wm_space_outliner(C); - return (so != NULL) && ELEM(so->outlinevis, SO_COLLECTIONS, SO_VIEW_LAYER, SO_SCENES); + return (so != NULL) && ELEM(so->outlinevis, SO_VIEW_LAYER, SO_SCENES); } @@ -145,19 +145,17 @@ static int collection_new_exec(bContext *C, wmOperator *op) .collection = NULL, }; - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data); + if (RNA_boolean_get(op->ptr, "nested")) { + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data); - if (data.error) { - BKE_report(op->reports, RPT_ERROR, "More than one collection is selected"); - return OPERATOR_CANCELLED; + if (data.error) { + BKE_report(op->reports, RPT_ERROR, "More than one collection is selected"); + return OPERATOR_CANCELLED; + } } - if (!data.collection) { - if (!(soops->outlinevis == SO_COLLECTIONS && - ELEM(soops->filter_collection, SO_FILTER_COLLECTION_UNLINKED, SO_FILTER_COLLECTION_ALL))) - { - data.collection = BKE_collection_master(scene); - } + if (!data.collection && (soops->outlinevis == SO_VIEW_LAYER)) { + data.collection = BKE_collection_master(scene); } BKE_collection_add( @@ -184,6 +182,10 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + PropertyRNA *prop = RNA_def_boolean(ot->srna, "nested", true, "Nested", "Add as child of selected collection");; + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /**************************** Delete Collection ******************************/ @@ -265,7 +267,8 @@ void OUTLINER_OT_collection_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_boolean(ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections"); + PropertyRNA *prop = RNA_def_boolean(ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /****************************** Select Objects *******************************/ @@ -285,6 +288,8 @@ static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeEle data->layer_collection = te->directdata; return TRAVERSE_BREAK; case TSE_R_LAYER: + case TSE_SCENE_COLLECTION_BASE: + case TSE_VIEW_COLLECTION_BASE: return TRAVERSE_CONTINUE; default: return TRAVERSE_SKIP_CHILDS; @@ -365,6 +370,8 @@ static TreeTraversalAction outliner_find_first_selected_collection(TreeElement * data->te = te; return TRAVERSE_BREAK; case TSE_R_LAYER: + case TSE_SCENE_COLLECTION_BASE: + case TSE_VIEW_COLLECTION_BASE: default: return TRAVERSE_CONTINUE; } @@ -400,7 +407,7 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op) switch (soops->outlinevis) { case SO_SCENES: case SO_VIEW_LAYER: - case SO_COLLECTIONS: + case SO_LIBRARIES: BKE_collection_copy(bmain, parent, collection); break; } @@ -538,3 +545,153 @@ void OUTLINER_OT_collection_instance(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/************************** Exclude Collection ******************************/ + +static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata) +{ + struct CollectionEditData *data = customdata; + TreeStoreElem *tselem = TREESTORE(te); + + if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) { + return TRAVERSE_CONTINUE; + } + + LayerCollection *lc = te->directdata; + + if (lc->collection->flag & COLLECTION_IS_MASTER) { + /* skip - showing warning/error message might be missleading + * when deleting multiple collections, so just do nothing */ + } + else { + /* Delete, duplicate and link don't edit children, those will come along + * with the parents. */ + BLI_gset_add(data->collections_to_edit, lc); + } + + return TRAVERSE_CONTINUE; +} + +static int collections_view_layer_poll(bContext *C, bool include) +{ + /* Poll function so the right click menu show current state of selected collections. */ + SpaceOops *soops = CTX_wm_space_outliner(C); + if (!(soops && soops->outlinevis == SO_VIEW_LAYER)) { + return false; + } + + Scene *scene = CTX_data_scene(C); + struct CollectionEditData data = {.scene = scene, .soops = soops}; + data.collections_to_edit = BLI_gset_ptr_new(__func__); + bool result = false; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); + + GSetIterator collections_to_edit_iter; + GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { + LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter); + + if (include && (lc->flag & LAYER_COLLECTION_EXCLUDE)) { + result = true; + } + else if (!include && !(lc->flag & LAYER_COLLECTION_EXCLUDE)) { + result = true; + } + } + + BLI_gset_free(data.collections_to_edit, NULL); + return result; +} + +static int collections_exclude_poll(bContext *C) +{ + return collections_view_layer_poll(C, false); +} + +static int collections_include_poll(bContext *C) +{ + return collections_view_layer_poll(C, true); +} + +static void layer_collection_exclude_recursive_set(LayerCollection *lc) +{ + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + if (lc->flag & LAYER_COLLECTION_EXCLUDE) { + nlc->flag |= LAYER_COLLECTION_EXCLUDE; + } + else { + nlc->flag &= ~LAYER_COLLECTION_EXCLUDE; + } + + layer_collection_exclude_recursive_set(nlc); + } +} + +static int collection_view_layer_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + struct CollectionEditData data = {.scene = scene, .soops = soops}; + bool include = STREQ(op->idname, "OUTLINER_OT_collection_include_set"); + + data.collections_to_edit = BLI_gset_ptr_new(__func__); + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); + + GSetIterator collections_to_edit_iter; + GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { + LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter); + + if (!(lc->collection->flag & COLLECTION_IS_MASTER)) { + if (include) { + lc->flag &= ~LAYER_COLLECTION_EXCLUDE; + } + else { + lc->flag |= LAYER_COLLECTION_EXCLUDE; + } + + layer_collection_exclude_recursive_set(lc); + } + } + + BLI_gset_free(data.collections_to_edit, NULL); + + BKE_layer_collection_sync(scene, view_layer); + DEG_relations_tag_update(bmain); + + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_exclude_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Exclude from View Layer"; + ot->idname = "OUTLINER_OT_collection_exclude_set"; + ot->description = "Exclude collection from the active view layer"; + + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_exclude_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_include_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Include in View Layer"; + ot->idname = "OUTLINER_OT_collection_include_set"; + ot->description = "Include collection in the active view layer"; + + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_include_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index d92b5df56be..90b137bcd7d 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -262,38 +262,6 @@ static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void } } -static void layer_collection_exclude_recursive_set(LayerCollection *lc) -{ - for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { - if (lc->flag & LAYER_COLLECTION_EXCLUDE) { - nlc->flag |= LAYER_COLLECTION_EXCLUDE; - } - else { - nlc->flag &= ~LAYER_COLLECTION_EXCLUDE; - } - - layer_collection_exclude_recursive_set(nlc); - } -} - -static void layer_collection_exclude_cb(bContext *C, void *poin, void *poin2) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = (Scene *)poin; - LayerCollection *lc = (LayerCollection *)poin2; - ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, lc); - - layer_collection_exclude_recursive_set(lc); - - BKE_layer_collection_sync(scene, view_layer); - - /* TODO(sergey): Use proper flag for tagging here. */ - DEG_id_tag_update(&scene->id, 0); - DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); -} - - static void namebutton_cb(bContext *C, void *tsep, char *oldname) { Main *bmain = CTX_data_main(C); @@ -423,10 +391,6 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, gpd); break; } - case TSE_R_LAYER: - { - break; - } case TSE_LAYER_COLLECTION: { BLI_libblock_ensure_unique_name(bmain, tselem->id->name); @@ -450,15 +414,12 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar PropertyRNA *collection_prop_hide_viewport; PropertyRNA *collection_prop_hide_select; PropertyRNA *collection_prop_hide_render; - PropertyRNA *collection_prop_exclude; collection_prop_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select"); collection_prop_hide_viewport = RNA_struct_type_find_property(&RNA_Collection, "hide_viewport"); collection_prop_hide_render = RNA_struct_type_find_property(&RNA_Collection, "hide_render"); - collection_prop_exclude = RNA_struct_type_find_property(&RNA_LayerCollection, "use"); BLI_assert(collection_prop_hide_viewport && collection_prop_hide_select && - collection_prop_hide_render && - collection_prop_exclude); + collection_prop_hide_render); for (te = lb->first; te; te = te->next) { tselem = TREESTORE(te); @@ -568,20 +529,9 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar UI_block_emboss_set(block, UI_EMBOSS_NONE); - if (soops->outlinevis == SO_VIEW_LAYER) { - if (lc && !(collection->flag & COLLECTION_IS_MASTER)) { - PointerRNA layer_collection_ptr; - RNA_pointer_create(&scene->id, &RNA_LayerCollection, lc, &layer_collection_ptr); - - bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, - (lc->flag & LAYER_COLLECTION_EXCLUDE) ? ICON_CHECKBOX_DEHLT : ICON_CHECKBOX_HLT, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &layer_collection_ptr, collection_prop_exclude, -1, 0, 0, 0, 0, NULL); - UI_but_func_set(bt, layer_collection_exclude_cb, scene, lc); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - } - } - else if (!lc || !(lc->flag & LAYER_COLLECTION_EXCLUDE)) { + if ((!lc || !(lc->flag & LAYER_COLLECTION_EXCLUDE)) && + !(collection->flag & COLLECTION_IS_MASTER)) + { PointerRNA collection_ptr; RNA_id_pointer_create(&collection->id, &collection_ptr); @@ -1111,6 +1061,7 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto break; case TSE_LAYER_COLLECTION: case TSE_SCENE_COLLECTION_BASE: + case TSE_VIEW_COLLECTION_BASE: ICON_DRAW(ICON_GROUP); break; /* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */ @@ -1249,6 +1200,11 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto } break; } + case ID_BR: + tselem_draw_icon_uibut(&arg, ICON_BRUSH_DATA); break; + case ID_SCR: + case ID_WS: + tselem_draw_icon_uibut(&arg, ICON_SPLITSCREEN); break; default: break; } @@ -1320,10 +1276,11 @@ static void outliner_draw_iconrow( } /* this tree element always has same amount of branches, so don't draw */ - if (tselem->type != TSE_R_LAYER) + if (tselem->type != TSE_R_LAYER) { outliner_draw_iconrow( C, block, scene, view_layer, obedit, soops, &te->subtree, level + 1, xmax, offsx, ys, alpha_fac); + } } } @@ -1442,8 +1399,8 @@ static void outliner_draw_tree_element( te->flag |= TE_ACTIVE; // for lookup in display hierarchies } - if (tselem->type == TSE_R_LAYER && ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS, SO_OBJECTS)) { - /* View layer in collections can't expand/collapse. */ + if (tselem->type == TSE_VIEW_COLLECTION_BASE) { + /* Scene collection in view layer can't expand/collapse. */ } else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) { /* open/close icon, only when sublevels, except for scene */ @@ -1461,7 +1418,7 @@ static void outliner_draw_tree_element( /* datatype icon */ - if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM))) { + if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE))) { tselem_draw_icon(block, xmax, (float)startx + offsx, (float)*starty, tselem, te, alpha_fac); offsx += UI_UNIT_X + 2 * ufac; } @@ -1746,7 +1703,7 @@ static void outliner_draw_highlights_recursive( int start_x, int *io_start_y) { const bool is_searching = SEARCHING_OUTLINER(soops) || - (soops->outlinevis == SO_DATABLOCKS && + (soops->outlinevis == SO_DATA_API && (soops->filter & SO_FILTER_SEARCH) && soops->search_string[0] != 0); @@ -1814,7 +1771,7 @@ static void outliner_draw_tree( glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // only once - if (soops->outlinevis == SO_DATABLOCKS) { + if (soops->outlinevis == SO_DATA_API) { /* struct marks */ starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; outliner_draw_struct_marks(ar, soops, &soops->tree, &starty); @@ -1940,7 +1897,7 @@ void draw_outliner(const bContext *C) /* get extents of data */ outliner_height(soops, &soops->tree, &sizey); - if (soops->outlinevis == SO_DATABLOCKS) { + if (soops->outlinevis == SO_DATA_API) { /* RNA has two columns: * - column 1 is (max_width + OL_RNA_COL_SPACEX) or * (OL_RNA_COL_X), whichever is wider... @@ -1990,7 +1947,7 @@ void draw_outliner(const bContext *C) (bContext *)C, block, scene, view_layer, obedit, ar, soops, has_restrict_icons, &te_edit); - if (soops->outlinevis == SO_DATABLOCKS) { + if (soops->outlinevis == SO_DATA_API) { /* draw rna buttons */ outliner_draw_rnacols(ar, sizex_rna); outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 4bb2f49fd08..5922e208f36 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -264,7 +264,8 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, /* do nothing */; } else if (ELEM(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE, - TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE)) + TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_SCENE_COLLECTION_BASE, + TSE_VIEW_COLLECTION_BASE)) { BKE_report(reports, RPT_WARNING, "Cannot edit builtin name"); } @@ -1338,7 +1339,7 @@ static int ed_operator_outliner_datablocks_active(bContext *C) ScrArea *sa = CTX_wm_area(C); if ((sa) && (sa->spacetype == SPACE_OUTLINER)) { SpaceOops *so = CTX_wm_space_outliner(C); - return (so->outlinevis == SO_DATABLOCKS); + return (so->outlinevis == SO_DATA_API); } return 0; } @@ -2063,7 +2064,12 @@ static int outliner_parenting_poll(bContext *C) SpaceOops *soops = CTX_wm_space_outliner(C); if (soops) { - if (ELEM(soops->outlinevis, SO_SCENES, SO_OBJECTS)) { + if (soops->outlinevis == SO_SCENES) { + return true; + } + else if ((soops->outlinevis == SO_VIEW_LAYER) && + (soops->filter & SO_FILTER_NO_COLLECTION)) + { return true; } } diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 86208dcb22d..73494b890ed 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -163,7 +163,7 @@ typedef enum { /* The outliner display modes that support the filter system. * Note: keep it synced with space_outliner.py */ -#define SUPPORT_FILTER_OUTLINER(soops_) (ELEM((soops_)->outlinevis, SO_COLLECTIONS, SO_OBJECTS)) +#define SUPPORT_FILTER_OUTLINER(soops_) (ELEM((soops_)->outlinevis, SO_VIEW_LAYER)) /* Outliner Searching -- * @@ -345,6 +345,8 @@ void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot); void OUTLINER_OT_collection_link(struct wmOperatorType *ot); void OUTLINER_OT_collection_instance(struct wmOperatorType *ot); +void OUTLINER_OT_collection_exclude_set(struct wmOperatorType *ot); +void OUTLINER_OT_collection_include_set(struct wmOperatorType *ot); /* outliner_utils.c ---------------------------------------------- */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index d7a158b92a6..9c1b9bf2630 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -69,7 +69,7 @@ static int outliner_item_drag_drop_poll(bContext *C) SpaceOops *soops = CTX_wm_space_outliner(C); return ED_operator_outliner_active(C) && /* Only collection display modes supported for now. Others need more design work */ - ELEM(soops->outlinevis, SO_COLLECTIONS, SO_OBJECTS); + ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_LIBRARIES); } static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event) @@ -455,6 +455,8 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_collection_objects_deselect); WM_operatortype_append(OUTLINER_OT_collection_link); WM_operatortype_append(OUTLINER_OT_collection_instance); + WM_operatortype_append(OUTLINER_OT_collection_exclude_set); + WM_operatortype_append(OUTLINER_OT_collection_include_set); } static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf) diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 810b7815214..42fe70be527 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -681,6 +681,27 @@ static eOLDrawState tree_element_active_keymap_item( return OL_DRAWSEL_NONE; } +static eOLDrawState tree_element_active_master_collection( + bContext *C, TreeElement *UNUSED(te), const eOLSetState set) +{ + if (set == OL_SETSEL_NONE) { + ViewLayer *view_layer = CTX_data_view_layer(C); + LayerCollection *active = CTX_data_layer_collection(C); + + if (active == view_layer->layer_collections.first) { + return OL_DRAWSEL_NORMAL; + } + } + else { + ViewLayer *view_layer = CTX_data_view_layer(C); + LayerCollection *layer_collection = view_layer->layer_collections.first; + BKE_layer_collection_activate(view_layer, layer_collection); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + } + + return OL_DRAWSEL_NONE; +} + static eOLDrawState tree_element_active_layer_collection( bContext *C, TreeElement *te, const eOLSetState set) { @@ -695,7 +716,7 @@ static eOLDrawState tree_element_active_layer_collection( Scene *scene = CTX_data_scene(C); LayerCollection *layer_collection = te->directdata; ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection); - view_layer->active_collection = layer_collection; + BKE_layer_collection_activate(view_layer, layer_collection); WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); } @@ -763,12 +784,7 @@ eOLDrawState tree_element_type_active( case TSE_CONSTRAINT: return tree_element_active_constraint(C, scene, view_layer, te, tselem, set); case TSE_R_LAYER: - if (soops->outlinevis == SO_SCENES) { - return active_viewlayer(C, scene, view_layer, te, tselem, set); - } - else { - return OL_DRAWSEL_NONE; - } + return active_viewlayer(C, scene, view_layer, te, tselem, set); case TSE_POSEGRP: return tree_element_active_posegroup(C, scene, view_layer, te, tselem, set); case TSE_SEQUENCE: @@ -780,6 +796,8 @@ eOLDrawState tree_element_type_active( case TSE_GP_LAYER: //return tree_element_active_gplayer(C, scene, s, te, tselem, set); break; + case TSE_VIEW_COLLECTION_BASE: + return tree_element_active_master_collection(C, te, set); case TSE_LAYER_COLLECTION: return tree_element_active_layer_collection(C, te, set); } @@ -905,7 +923,7 @@ static bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_ static bool outliner_is_co_within_restrict_columns(const SpaceOops *soops, const ARegion *ar, float view_co_x) { - return ((soops->outlinevis != SO_DATABLOCKS) && + return ((soops->outlinevis != SO_DATA_API) && !(soops->flag & SO_HIDE_RESTRICTCOLS) && (view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)); } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 6ee8b354772..5ae6cec84ba 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -105,11 +105,8 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb, for (te = lb->first; te; te = te->next) { tselem = TREESTORE(te); if (tselem->flag & TSE_SELECTED) { - if (tselem->type == TSE_R_LAYER && soops->outlinevis == SO_COLLECTIONS) { - /* Don't let immutable render layer item affect menu. */ - } - else if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { - /* Layer collection points to collection ID. */ + /* Layer collection points to collection ID. */ + if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { if (*datalevel == 0) *datalevel = tselem->type; else if (*datalevel != tselem->type) @@ -133,6 +130,9 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb, case ID_LI: if (*idlevel == 0) *idlevel = idcode; else if (*idlevel != idcode) *idlevel = -1; + if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) { + *datalevel = 0; + } break; } } @@ -1824,12 +1824,9 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop else if (datalevel == TSE_LAYER_COLLECTION) { WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN); } - else if (datalevel == TSE_R_LAYER && ELEM(soops->outlinevis, SO_COLLECTIONS, SO_VIEW_LAYER)) { + else if (ELEM(datalevel, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); } - else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER)) { - /*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/ - } else if (datalevel == TSE_ID_BASE) { /* do nothing... there are no ops needed here yet */ } @@ -1880,7 +1877,7 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent if (!found) { /* Menus for clicking in empty space. */ - if (ELEM(soops->outlinevis, SO_COLLECTIONS, SO_VIEW_LAYER)) { + if (soops->outlinevis == SO_VIEW_LAYER) { WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); } } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 22d70a12261..58ab8f3735e 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -299,7 +299,7 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s /* Collections */ ten = outliner_add_element(soops, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0); - ten->name = IFACE_("Collections"); + ten->name = IFACE_("Scene Collection"); outliner_add_collection_recursive(soops, sce->master_collection, ten); /* Objects */ @@ -877,7 +877,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i else if (type == TSE_GP_LAYER) { /* pass */ } - else if (ELEM(type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE)) { + else if (ELEM(type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { /* pass */ } else if (type == TSE_ID_BASE) { @@ -896,8 +896,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL; /* ID datablock */ - if (tsepar == NULL || tsepar->type != TSE_ID_BASE) + if (tsepar == NULL || tsepar->type != TSE_ID_BASE || soops->filter_id_type) { outliner_add_id_contents(soops, te, tselem, id); + } } else if (type == TSE_ANIM_DATA) { IdAdtTemplate *iat = (IdAdtTemplate *)idv; @@ -1252,16 +1253,56 @@ static void outliner_add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *t /* ----------------------------------------------- */ +static const char *outliner_idcode_to_plural(short idcode) +{ + const char *propname = BKE_idcode_to_name_plural(idcode); + PropertyRNA *prop = RNA_struct_type_find_property(&RNA_BlendData, propname); + return (prop) ? RNA_property_ui_name(prop) : "UNKNOWN"; +} + +static bool outliner_library_id_show(Library *lib, ID *id, short filter_id_type) +{ + if (id->lib != lib) { + return false; + } + + if (filter_id_type == ID_GR) { + /* Don't show child collections of non-scene master collection, + * they are already shown as children. */ + Collection *collection = (Collection *)id; + bool has_non_scene_parent = false; + + for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) { + if (!(cparent->collection->flag & COLLECTION_IS_MASTER)) { + has_non_scene_parent = true; + } + } + + if (has_non_scene_parent) { + return false; + } + } + + return true; +} static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeElement *te, Library *lib) { TreeElement *ten; ListBase *lbarray[MAX_LIBARRAY]; int a, tot; + short filter_id_type = (soops->filter & SO_FILTER_ID_TYPE) ? soops->filter_id_type : 0; - tot = set_listbasepointers(mainvar, lbarray); + if (filter_id_type) { + lbarray[0] = which_libbase(mainvar, soops->filter_id_type); + tot = 1; + } + else { + tot = set_listbasepointers(mainvar, lbarray); + } + for (a = 0; a < tot; a++) { - if (lbarray[a]->first) { + if (lbarray[a] && lbarray[a]->first) { ID *id = lbarray[a]->first; /* check if there's data in current lib */ @@ -1270,21 +1311,23 @@ static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeE break; if (id) { - ten = outliner_add_element(soops, &te->subtree, lbarray[a], NULL, TSE_ID_BASE, 0); - ten->directdata = lbarray[a]; - - ten->name = BKE_idcode_to_name_plural(GS(id->name)); - if (ten->name == NULL) - ten->name = "UNKNOWN"; + if (filter_id_type) { + ten = te; + } + else { + ten = outliner_add_element(soops, &te->subtree, lbarray[a], NULL, TSE_ID_BASE, 0); + ten->directdata = lbarray[a]; + ten->name = outliner_idcode_to_plural(GS(id->name)); + } for (id = lbarray[a]->first; id; id = id->next) { - if (id->lib == lib) + if (outliner_library_id_show(lib, id, filter_id_type)) { outliner_add_element(soops, &ten->subtree, id, ten, 0, 0); + } } } } } - } static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops) @@ -1292,10 +1335,18 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops) TreeElement *ten; ListBase *lbarray[MAX_LIBARRAY]; int a, tot; + short filter_id_type = (soops->filter & SO_FILTER_ID_TYPE) ? soops->filter_id_type : 0; - tot = set_listbasepointers(mainvar, lbarray); + if (filter_id_type) { + lbarray[0] = which_libbase(mainvar, soops->filter_id_type); + tot = 1; + } + else { + tot = set_listbasepointers(mainvar, lbarray); + } + for (a = 0; a < tot; a++) { - if (lbarray[a]->first) { + if (lbarray[a] && lbarray[a]->first) { ID *id = lbarray[a]->first; /* check if there are any datablocks of this type which are orphans */ @@ -1306,21 +1357,19 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops) if (id) { /* header for this type of datablock */ - /* TODO's: - * - Add a parameter to BKE_idcode_to_name_plural to get a sane "user-visible" name instead? - * - Ensure that this uses nice icons for the datablock type involved instead of the dot? - */ - ten = outliner_add_element(soops, &soops->tree, lbarray[a], NULL, TSE_ID_BASE, 0); - ten->directdata = lbarray[a]; - - ten->name = BKE_idcode_to_name_plural(GS(id->name)); - if (ten->name == NULL) - ten->name = "UNKNOWN"; + if (filter_id_type) { + ten = NULL; + } + else { + ten = outliner_add_element(soops, &soops->tree, lbarray[a], NULL, TSE_ID_BASE, 0); + ten->directdata = lbarray[a]; + ten->name = outliner_idcode_to_plural(GS(id->name)); + } /* add the orphaned datablocks - these will not be added with any subtrees attached */ for (id = lbarray[a]->first; id; id = id->next) { if (ID_REAL_USERS(id) <= 0) - outliner_add_element(soops, &ten->subtree, id, ten, 0, 0); + outliner_add_element(soops, (ten) ? &ten->subtree : &soops->tree, id, ten, 0, 0); } } } @@ -1412,33 +1461,12 @@ static void outliner_add_layer_collection_objects( } } -static bool outliner_layer_collection_is_visible(LayerCollection *lc) -{ - if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) { - return true; - } - - for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { - if (outliner_layer_collection_is_visible(nlc)) { - return true; - } - } - - return false; -} - static void outliner_add_layer_collections_recursive( SpaceOops *soops, ListBase *tree, ViewLayer *layer, ListBase *layer_collections, TreeElement *parent_ten, const bool show_objects) { for (LayerCollection *lc = layer_collections->first; lc; lc = lc->next) { - if ((soops->outlinevis != SO_VIEW_LAYER) && - !outliner_layer_collection_is_visible(lc)) - { - continue; - } - ID *id = &lc->collection->id; TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0); @@ -1477,7 +1505,7 @@ static void outliner_add_view_layer(SpaceOops *soops, ListBase *tree, TreeElemen BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collection) { if (collection->flag & COLLECTION_IS_MASTER) { - te->name = IFACE_("Collections"); + te->name = IFACE_("Scene Collection"); } else { te->name = collection->id.name + 2; @@ -1776,7 +1804,8 @@ static TreeElement *outliner_find_first_desired_element_at_y( te = outliner_find_item_at_y(soops, &soops->tree, view_co); bool (*callback_test)(TreeElement *); - if (soops->outlinevis == SO_OBJECTS) { + if ((soops->outlinevis == SO_VIEW_LAYER) && + (soops->filter & SO_FILTER_NO_COLLECTION)) { callback_test = test_object_callback; } else { @@ -1855,7 +1884,7 @@ static int outliner_exclude_filter_get(SpaceOops *soops) return (exclude_filter & SO_FILTER_SEARCH); } - if (soops->outlinevis == SO_COLLECTIONS && (soops->filter & SO_FILTER_NO_OBJECT)) { + if (soops->filter & SO_FILTER_NO_OBJECT) { exclude_filter |= SO_FILTER_OB_TYPE; } @@ -2070,7 +2099,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa /* Are we looking for something - we want to tag parents to filter child matches * - NOT in datablocks view - searching all datablocks takes way too long to be useful * - this variable is only set once per tree build */ - if (soops->search_string[0] != 0 && soops->outlinevis != SO_DATABLOCKS) + if (soops->search_string[0] != 0 && soops->outlinevis != SO_DATA_API) soops->search_flags |= SO_SEARCH_RECURSIVE; else soops->search_flags &= ~SO_SEARCH_RECURSIVE; @@ -2177,7 +2206,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa seq = seq->next; } } - else if (soops->outlinevis == SO_DATABLOCKS) { + else if (soops->outlinevis == SO_DATA_API) { PointerRNA mainptr; RNA_main_pointer_create(mainvar, &mainptr); @@ -2192,59 +2221,25 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa else if (soops->outlinevis == SO_ID_ORPHANS) { outliner_add_orphaned_datablocks(mainvar, soops); } - else if (soops->outlinevis == SO_COLLECTIONS && - soops->filter_collection != SO_FILTER_COLLECTION_SCENE) { - Collection *collection; - for (collection = mainvar->collection.first; collection; collection = collection->id.next) { - if (soops->filter_collection == SO_FILTER_COLLECTION_UNLINKED) { - /* Skip collections used in a scene */ - if (BKE_collection_is_in_scene(collection)) { - continue; - } - } - - if (collection->parents.first) { - /* Don't show child collections of non-scene master collection, - * they are already shown as children. */ - bool has_non_scene_parent = false; - - for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) { - if (!(cparent->collection->flag & COLLECTION_IS_MASTER)) { - has_non_scene_parent = true; - } - } - - if (has_non_scene_parent) { - continue; - } + else if (soops->outlinevis == SO_VIEW_LAYER) { + if (soops->filter & SO_FILTER_NO_COLLECTION) { + /* Show objects in the view layer. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + TreeElement *te_object = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); + te_object->directdata = base; } - te = outliner_add_element(soops, &soops->tree, collection, NULL, 0, 0); + outliner_make_object_parent_hierarchy(&soops->tree); } - } - else if (ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS)) { - /* Show collections and objects in the view layer. */ - TreeElement *tenlay = outliner_add_element(soops, &soops->tree, scene, te, TSE_R_LAYER, 0); - tenlay->name = view_layer->name; - tenlay->directdata = view_layer; - TREESTORE(tenlay)->flag &= ~TSE_CLOSED; - - bool show_objects = (soops->outlinevis == SO_COLLECTIONS) && - !(soops->filter & SO_FILTER_NO_OBJECT); - outliner_add_view_layer(soops, &tenlay->subtree, tenlay, view_layer, show_objects); - } - else { /* SO_OBJECTS */ - /* Show objects in the view layer. */ - TreeElement *tenlay = outliner_add_element(soops, &soops->tree, scene, te, TSE_R_LAYER, 0); - tenlay->name = view_layer->name; - tenlay->directdata = view_layer; - TREESTORE(tenlay)->flag &= ~TSE_CLOSED; + else { + /* Show collections in the view layer. */ + ten = outliner_add_element(soops, &soops->tree, scene, NULL, TSE_VIEW_COLLECTION_BASE, 0); + ten->name = IFACE_("Scene Collection"); + TREESTORE(ten)->flag &= ~TSE_CLOSED; - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - TreeElement *te_object = outliner_add_element(soops, &tenlay->subtree, base->object, NULL, 0, 0); - te_object->directdata = base; + bool show_objects = !(soops->filter & SO_FILTER_NO_OBJECT); + outliner_add_view_layer(soops, &ten->subtree, ten, view_layer, show_objects); } - outliner_make_object_parent_hierarchy(&tenlay->subtree); } if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) { diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index dc6406fcc18..72ce24aaff5 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -159,7 +159,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent * UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - if (!ELEM(soops->outlinevis, SO_SCENES, SO_COLLECTIONS, SO_OBJECTS)) { + if (!ELEM(soops->outlinevis, SO_VIEW_LAYER)) { return false; } @@ -434,7 +434,7 @@ static void outliner_main_region_message_subscribe( .notify = ED_region_do_msg_notify_tag_redraw, }; - if (ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS, SO_OBJECTS)) { + if (ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_SCENES)) { WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); } } @@ -483,6 +483,7 @@ static SpaceLink *outliner_new(const ScrArea *UNUSED(area), const Scene *UNUSED( soutliner = MEM_callocN(sizeof(SpaceOops), "initoutliner"); soutliner->spacetype = SPACE_OUTLINER; + soutliner->filter_id_type = ID_GR; /* header */ ar = MEM_callocN(sizeof(ARegion), "header for outliner"); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index ede18b73175..3f795651c65 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1017,7 +1017,7 @@ static void view3d_main_region_listener( static void view3d_main_region_message_subscribe( const struct bContext *C, - struct WorkSpace *workspace, struct Scene *scene, + struct WorkSpace *workspace, struct Scene *UNUSED(scene), struct bScreen *UNUSED(screen), struct ScrArea *UNUSED(sa), struct ARegion *ar, struct wmMsgBus *mbus) { @@ -1075,19 +1075,7 @@ static void view3d_main_region_message_subscribe( WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, use_border, &msg_sub_value_region_tag_redraw); } - /* Each engine could be responsible for its own engine data types. - * For now this is simplest. */ - if (STREQ(scene->r.engine, RE_engine_id_BLENDER_EEVEE)) { - extern StructRNA RNA_ViewLayerEngineSettingsEevee; - WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsEevee, &msg_sub_value_region_tag_redraw); - } -#ifdef WITH_CLAY_ENGINE - else if (STREQ(scene->r.engine, RE_engine_id_BLENDER_CLAY)) { - extern StructRNA RNA_ViewLayerEngineSettingsClay; - WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsClay, &msg_sub_value_region_tag_redraw); - } -#endif - + WM_msg_subscribe_rna_anon_type(mbus, SceneEEVEE, &msg_sub_value_region_tag_redraw); WM_msg_subscribe_rna_anon_type(mbus, SceneDisplay, &msg_sub_value_region_tag_redraw); WM_msg_subscribe_rna_anon_type(mbus, ObjectDisplay, &msg_sub_value_region_tag_redraw); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index a3990091b12..c479267603d 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -4607,7 +4607,7 @@ void ED_view3d_cursor3d_update(bContext *C, const int mval[2]) .snap_select = SNAP_ALL, .use_object_edit_cage = false, }, - mval_fl, &dist_px, NULL, + mval_fl, &dist_px, cursor_curr->location, ray_no, NULL, &ob_dummy, obmat)) { diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 3c026f71769..12229b8c940 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -2027,7 +2027,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) if (!(point->flag & PEP_TRANSFORM)) continue; if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) - psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + i, mat); + psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, psys->particles + i, mat); for (k = 0, key = point->keys; k < point->totkey; k++, key++) { if (key->flag & PEK_USE_WCO) { @@ -2105,7 +2105,7 @@ void flushTransParticles(TransInfo *t) if (!(point->flag & PEP_TRANSFORM)) continue; if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) { - psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + i, mat); + psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, psys->particles + i, mat); invert_m4_m4(imat, mat); for (k = 0, key = point->keys; k < point->totkey; k++, key++) { diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 681f955087a..948eb47965f 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1195,16 +1195,15 @@ bool snapObjectsTransform( float *dist_px, float r_loc[3], float r_no[3]) { - return ED_transform_snap_object_project_view3d_ex( + return ED_transform_snap_object_project_view3d( t->tsnap.object_context, t->scene->toolsettings->snap_mode, &(const struct SnapObjectParams){ .snap_select = t->tsnap.modeSelect, .use_object_edit_cage = (t->flag & T_EDIT) != 0, + .use_occlusion_test = t->scene->toolsettings->snap_mode != SCE_SNAP_MODE_FACE, }, - mval, dist_px, NULL, - r_loc, r_no, NULL, - NULL, NULL); + mval, dist_px, r_loc, r_no); } diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index eb8fa0480ce..ec3f9793889 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -71,6 +71,8 @@ /** Internal Data Types * \{ */ +#define MAX_CLIPPLANE_LEN 3 + enum eViewProj { VIEW_PROJ_NONE = -1, VIEW_PROJ_ORTHO = 0, @@ -80,12 +82,11 @@ enum eViewProj { typedef struct SnapData { short snap_to; float mval[2]; - float ray_start[3]; - float ray_dir[3]; float pmat[4][4]; /* perspective matrix */ float win_size[2];/* win x and y */ enum eViewProj view_proj; - float depth_range[2]; + float clip_plane[MAX_CLIPPLANE_LEN][4]; + short clip_plane_len; } SnapData; typedef struct SnapObjectData { @@ -196,38 +197,6 @@ static void iter_snap_objects( } -/** - * Generates a struct with the immutable parameters that will be used on all objects. - * - * \param snap_to: Element to snap, Vertice, Edge or Face. - * \param view_proj: ORTHO or PERSP. - * Currently only works one at a time, but can eventually operate as flag. - * - * \param mval: Mouse coords. - * (When NULL, ray-casting is handled without any projection matrix correction.) - * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min. - * \param ray_start: ray_origin moved for the start clipping plane (clip_min). - * \param ray_direction: Unit length direction of the ray. - * \param depth_range: distances of clipe plane min and clip plane max; - */ -static void snap_data_set( - SnapData *snapdata, - const ARegion *ar, const unsigned short snap_to, const enum eViewProj view_proj, - const float mval[2], const float ray_start[3], const float ray_direction[3], - const float depth_range[2]) -{ - copy_m4_m4(snapdata->pmat, ((RegionView3D *)ar->regiondata)->persmat); - snapdata->win_size[0] = ar->winx; - snapdata->win_size[1] = ar->winy; - copy_v2_v2(snapdata->mval, mval); - snapdata->snap_to = snap_to; - copy_v3_v3(snapdata->ray_start, ray_start); - copy_v3_v3(snapdata->ray_dir, ray_direction); - snapdata->view_proj = view_proj; - copy_v2_v2(snapdata->depth_range, depth_range); -} - - MINLINE float depth_get(const float co[3], const float ray_start[3], const float ray_dir[3]) { float dvec[3]; @@ -682,7 +651,7 @@ static bool raycastObj( SnapObjectContext *sctx, const float ray_start[3], const float ray_dir[3], Object *ob, float obmat[4][4], const unsigned int ob_index, - bool use_obedit, + bool use_obedit, bool use_occlusion_test, /* read/write args */ float *ray_depth, /* return args */ @@ -692,6 +661,15 @@ static bool raycastObj( { bool retval = false; + if (use_occlusion_test) { + if (use_obedit && sctx->use_v3d && + !(sctx->v3d_data.v3d->flag & V3D_ZBUF_SELECT)) + { + /* Use of occlude geometry in editing mode disabled. */ + return false; + } + } + switch (ob->type) { case OB_MESH: if (use_obedit) { @@ -739,16 +717,19 @@ struct RaycastObjUserData { Object **r_ob; float (*r_obmat)[4]; ListBase *r_hit_list; + bool use_occlusion_test; bool ret; }; static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data) { struct RaycastObjUserData *dt = data; + dt->ret |= raycastObj( sctx, dt->ray_start, dt->ray_dir, - ob, obmat, dt->ob_index++, is_obedit, + ob, obmat, dt->ob_index++, + is_obedit, dt->use_occlusion_test, dt->ray_depth, dt->r_loc, dt->r_no, dt->r_index, dt->r_ob, dt->r_obmat, @@ -805,6 +786,7 @@ static bool raycastObjects( .r_ob = r_ob, .r_obmat = r_obmat, .r_hit_list = r_hit_list, + .use_occlusion_test = params->use_occlusion_test, .ret = false, }; @@ -900,29 +882,26 @@ static void cb_mlooptri_verts_get( } static bool test_projected_vert_dist( - const struct DistProjectedAABBPrecalc *neasrest_precalc, - const float depth_range[2], + const struct DistProjectedAABBPrecalc *precalc, + const float (*clip_plane)[4], const int clip_plane_len, const bool is_persp, const float co[3], float *dist_px_sq, float r_co[3]) { - float w; - if (is_persp) { - w = mul_project_m4_v3_zfac(neasrest_precalc->pmat, co); - if (w < depth_range[0] || w > depth_range[1]) { - return false; - } + if (!isect_point_planes_v3_negated(clip_plane, clip_plane_len, co)) { + return false; } float co2d[2] = { - (dot_m4_v3_row_x(neasrest_precalc->pmat, co) + neasrest_precalc->pmat[3][0]), - (dot_m4_v3_row_y(neasrest_precalc->pmat, co) + neasrest_precalc->pmat[3][1]), + (dot_m4_v3_row_x(precalc->pmat, co) + precalc->pmat[3][0]), + (dot_m4_v3_row_y(precalc->pmat, co) + precalc->pmat[3][1]), }; if (is_persp) { + float w = mul_project_m4_v3_zfac(precalc->pmat, co); mul_v2_fl(co2d, 1.0f / w); } - const float dist_sq = len_squared_v2v2(neasrest_precalc->mval, co2d); + const float dist_sq = len_squared_v2v2(precalc->mval, co2d); if (dist_sq < *dist_px_sq) { copy_v3_v3(r_co, co); *dist_px_sq = dist_sq; @@ -932,23 +911,158 @@ static bool test_projected_vert_dist( } static bool test_projected_edge_dist( - const struct DistProjectedAABBPrecalc *neasrest_precalc, - const float depth_range[2], const bool is_persp, - const float va[3], const float vb[3], + const struct DistProjectedAABBPrecalc *precalc, + const float (*clip_plane)[4], const int clip_plane_len, + const bool is_persp, const float va[3], const float vb[3], float *dist_px_sq, float r_co[3]) { - - float near_co[3], dummy_depth; - dist_squared_ray_to_seg_v3( - neasrest_precalc->ray_origin, - neasrest_precalc->ray_direction, - va, vb, near_co, &dummy_depth); + float near_co[3], lambda; + if (!isect_ray_seg_v3( + precalc->ray_origin, + precalc->ray_direction, + va, vb, &lambda)) + { + copy_v3_v3(near_co, va); + } + else { + if (lambda <= 0.0f) { + copy_v3_v3(near_co, va); + } + else if (lambda >= 1.0f) { + copy_v3_v3(near_co, vb); + } + else { + interp_v3_v3v3(near_co, va, vb, lambda); + } + } return test_projected_vert_dist( - neasrest_precalc, depth_range, + precalc, clip_plane, clip_plane_len, is_persp, near_co, dist_px_sq, r_co); } +static bool snapMeshPolygon( + SnapObjectContext *sctx, SnapData *snapdata, + Object *ob, float obmat[4][4], + /* read/write args */ + float *dist_px, + /* return args */ + float r_loc[3], float r_no[3], int *r_index) +{ + bool retval = false; + + float lpmat[4][4], dist_px_sq = SQUARE(*dist_px); + mul_m4_m4m4(lpmat, snapdata->pmat, obmat); + + struct DistProjectedAABBPrecalc neasrest_precalc; + dist_squared_to_projected_aabb_precalc( + &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); + + float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; + transpose_m4_m4(tobmat, obmat); + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + + bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; + + SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob); + BLI_assert(sod != NULL); + + if (sod->type == SNAP_MESH) { + Mesh *me = ob->data; + MPoly *mp = &me->mpoly[*r_index]; + + const MLoop *ml = &me->mloop[mp->loopstart]; + for (int i = mp->totloop; i--; ml++) { + if (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) { + const MVert *vert = &me->mvert[ml->v]; + if (test_projected_vert_dist( + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, + is_persp, vert->co, + &dist_px_sq, r_loc)) + { + normal_short_to_float_v3(r_no, vert->no); + *r_index = ml->v; + retval = true; + } + } + else { + float co_pair[2][3]; + const MEdge *edge = &me->medge[ml->e]; + copy_v3_v3(co_pair[0], me->mvert[edge->v1].co); + copy_v3_v3(co_pair[1], me->mvert[edge->v2].co); + if (test_projected_edge_dist( + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, + is_persp, co_pair[0], co_pair[1], + &dist_px_sq, r_loc)) + { + sub_v3_v3v3(r_no, co_pair[0], co_pair[1]); + *r_index = ml->e; + retval = true; + } + } + } + } + else { + BLI_assert(sod->type == SNAP_EDIT_MESH); + + BMEditMesh *em = BKE_editmesh_from_object(ob); + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + BMFace *f = BM_face_at_index(em->bm, *r_index); + + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + + do { + if (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) { + const float *co = l_iter->v->co; + if (test_projected_vert_dist( + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, + is_persp, co, + &dist_px_sq, r_loc)) + { + copy_v3_v3(r_no, l_iter->v->no); + *r_index = BM_elem_index_get(l_iter->v); + retval = true; + } + } + else { + float co_pair[2][3]; + copy_v3_v3(co_pair[0], l_iter->e->v1->co); + copy_v3_v3(co_pair[1], l_iter->e->v2->co); + if (test_projected_edge_dist( + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, + is_persp, co_pair[0], co_pair[1], + &dist_px_sq, r_loc)) + { + sub_v3_v3v3(r_no, co_pair[0], co_pair[1]); + *r_index = BM_elem_index_get(l_iter->e); + retval = true; + } + } + } while ((l_iter = l_iter->next) != l_first); + } + + if (retval) { + float imat[4][4]; + invert_m4_m4(imat, obmat); + + mul_m4_v3(obmat, r_loc); + mul_transposed_mat3_m4_v3(obmat, r_no); + normalize_v3(r_no); + + *dist_px = sqrtf(dist_px_sq); + + return true; + } + return false; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -963,7 +1077,6 @@ typedef void (*Nearest2DCopyVertNoCallback)(const int index, float r_no[3], void typedef struct Nearest2dUserData { bool is_persp; - float depth_range[2]; short snap_to; void *userdata; @@ -979,6 +1092,7 @@ typedef struct Nearest2dUserData { static void cb_walk_leaf_snap_vert( void *userdata, int index, const struct DistProjectedAABBPrecalc *precalc, + const float (*clip_plane)[4], const int clip_plane_len, BVHTreeNearest *nearest) { struct Nearest2dUserData *data = userdata; @@ -988,9 +1102,9 @@ static void cb_walk_leaf_snap_vert( if (test_projected_vert_dist( precalc, - data->depth_range, - data->is_persp, - co, + clip_plane, + clip_plane_len, + data->is_persp, co, &nearest->dist_sq, nearest->co)) { @@ -1002,6 +1116,7 @@ static void cb_walk_leaf_snap_vert( static void cb_walk_leaf_snap_edge( void *userdata, int index, const struct DistProjectedAABBPrecalc *precalc, + const float (*clip_plane)[4], const int clip_plane_len, BVHTreeNearest *nearest) { struct Nearest2dUserData *data = userdata; @@ -1016,7 +1131,8 @@ static void cb_walk_leaf_snap_edge( if (test_projected_edge_dist( precalc, - data->depth_range, + clip_plane, + clip_plane_len, data->is_persp, v_pair[0], v_pair[1], &nearest->dist_sq, @@ -1031,7 +1147,9 @@ static void cb_walk_leaf_snap_edge( if (vindex[i] == nearest->index) { continue; } - cb_walk_leaf_snap_vert(userdata, vindex[i], precalc, nearest); + cb_walk_leaf_snap_vert( + userdata, vindex[i], precalc, + clip_plane, clip_plane_len, nearest); } } } @@ -1039,6 +1157,7 @@ static void cb_walk_leaf_snap_edge( static void cb_walk_leaf_snap_tri( void *userdata, int index, const struct DistProjectedAABBPrecalc *precalc, + const float (*clip_plane)[4], const int clip_plane_len, BVHTreeNearest *nearest) { struct Nearest2dUserData *data = userdata; @@ -1051,7 +1170,9 @@ static void cb_walk_leaf_snap_tri( if (eindex[i] == nearest->index) { continue; } - cb_walk_leaf_snap_edge(userdata, eindex[i], precalc, nearest); + cb_walk_leaf_snap_edge( + userdata, eindex[i], precalc, + clip_plane, clip_plane_len, nearest); } } } @@ -1062,7 +1183,9 @@ static void cb_walk_leaf_snap_tri( if (vindex[i] == nearest->index) { continue; } - cb_walk_leaf_snap_vert(userdata, vindex[i], precalc, nearest); + cb_walk_leaf_snap_vert( + userdata, vindex[i], precalc, + clip_plane, clip_plane_len, nearest); } } } @@ -1075,11 +1198,11 @@ static void cb_walk_leaf_snap_tri( static bool snapArmature( SnapData *snapdata, - Object *ob, bArmature *arm, float obmat[4][4], + Object *ob, float obmat[4][4], bool use_obedit, /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float *UNUSED(r_no)) + float r_loc[3], float *UNUSED(r_no), int *r_index) { bool retval = false; @@ -1094,21 +1217,30 @@ static bool snapArmature( dist_squared_to_projected_aabb_precalc( &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); - /* Test BoundBox */ - BoundBox *bb = BKE_armature_boundbox_get(ob); - if (bb) { - bool dummy[3]; - /* In vertex and edges you need to get the pixel distance from ray to BoundBox, see: T46099, T46816 */ - float bb_dist_px_sq = dist_squared_to_projected_aabb( - &neasrest_precalc, bb->vec[0], bb->vec[6], dummy); - - if (bb_dist_px_sq > dist_px_sq) { - return retval; + if (use_obedit == false) { + /* Test BoundBox */ + BoundBox *bb = BKE_armature_boundbox_get(ob); + if (bb) { + bool dummy[3]; + /* In vertex and edges you need to get the pixel distance from ray to BoundBox, see: T46099, T46816 */ + float bb_dist_px_sq = dist_squared_to_projected_aabb( + &neasrest_precalc, bb->vec[0], bb->vec[6], dummy); + + if (bb_dist_px_sq > dist_px_sq) { + return retval; + } } } + float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; + transpose_m4_m4(tobmat, obmat); + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; + bArmature *arm = ob->data; if (arm->edbo) { for (EditBone *eBone = arm->edbo->first; eBone; eBone = eBone->next) { if (eBone->layer & arm->layer) { @@ -1117,15 +1249,18 @@ static bool snapArmature( switch (snapdata->snap_to) { case SCE_SNAP_MODE_VERTEX: retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, eBone->head, &dist_px_sq, r_loc); retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, eBone->tail, &dist_px_sq, r_loc); break; case SCE_SNAP_MODE_EDGE: retval |= test_projected_edge_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, eBone->head, eBone->tail, &dist_px_sq, r_loc); break; @@ -1145,15 +1280,18 @@ static bool snapArmature( switch (snapdata->snap_to) { case SCE_SNAP_MODE_VERTEX: retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, head_vec, &dist_px_sq, r_loc); retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, tail_vec, &dist_px_sq, r_loc); break; case SCE_SNAP_MODE_EDGE: retval |= test_projected_edge_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, head_vec, tail_vec, &dist_px_sq, r_loc); break; @@ -1164,7 +1302,10 @@ static bool snapArmature( if (retval) { *dist_px = sqrtf(dist_px_sq); mul_m4_v3(obmat, r_loc); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + if (r_index) { + /* Does not support index. */ + *r_index = -1; + } return true; } return false; @@ -1174,9 +1315,9 @@ static bool snapCurve( SnapData *snapdata, Object *ob, float obmat[4][4], bool use_obedit, /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float *UNUSED(r_no)) + float r_loc[3], float *UNUSED(r_no), int *r_index) { bool retval = false; @@ -1195,83 +1336,93 @@ static bool snapCurve( dist_squared_to_projected_aabb_precalc( &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); - /* Test BoundBox */ - BoundBox *bb = BKE_curve_boundbox_get(ob); - if (bb) { - bool dummy[3]; - /* In vertex and edges you need to get the pixel distance from ray to BoundBox, see: T46099, T46816 */ - float bb_dist_px_sq = dist_squared_to_projected_aabb( - &neasrest_precalc, bb->vec[0], bb->vec[6], dummy); - - if (bb_dist_px_sq > dist_px_sq) { - return retval; + if (use_obedit == false) { + /* Test BoundBox */ + BoundBox *bb = BKE_curve_boundbox_get(ob); + if (bb) { + bool dummy[3]; + /* In vertex and edges you need to get the pixel distance from ray to BoundBox, see: T46099, T46816 */ + float bb_dist_px_sq = dist_squared_to_projected_aabb( + &neasrest_precalc, bb->vec[0], bb->vec[6], dummy); + + if (bb_dist_px_sq > dist_px_sq) { + return retval; + } } } + float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; + transpose_m4_m4(tobmat, obmat); + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; for (Nurb *nu = (use_obedit ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) { for (int u = 0; u < nu->pntsu; u++) { - switch (snapdata->snap_to) { - case SCE_SNAP_MODE_VERTEX: - { - if (use_obedit) { + if (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) { + if (use_obedit) { + if (nu->bezt) { + /* don't snap to selected (moving) or hidden */ + if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) { + break; + } + retval |= test_projected_vert_dist( + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, + is_persp, nu->bezt[u].vec[1], &dist_px_sq, + r_loc); + /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */ + if (!(nu->bezt[u].f1 & SELECT) && + !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) + { + retval |= test_projected_vert_dist( + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, + is_persp, nu->bezt[u].vec[0], &dist_px_sq, + r_loc); + } + if (!(nu->bezt[u].f3 & SELECT) && + !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) + { + retval |= test_projected_vert_dist( + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, + is_persp, nu->bezt[u].vec[2], &dist_px_sq, + r_loc); + } + } + else { + /* don't snap to selected (moving) or hidden */ + if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) { + break; + } + retval |= test_projected_vert_dist( + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, + is_persp, nu->bp[u].vec, &dist_px_sq, + r_loc); + } + } + else { + /* curve is not visible outside editmode if nurb length less than two */ + if (nu->pntsu > 1) { if (nu->bezt) { - /* don't snap to selected (moving) or hidden */ - if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) { - break; - } retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, nu->bezt[u].vec[1], &dist_px_sq, r_loc); - /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */ - if (!(nu->bezt[u].f1 & SELECT) && - !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) - { - retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, - is_persp, nu->bezt[u].vec[0], &dist_px_sq, - r_loc); - } - if (!(nu->bezt[u].f3 & SELECT) && - !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) - { - retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, - is_persp, nu->bezt[u].vec[2], &dist_px_sq, - r_loc); - } } else { - /* don't snap to selected (moving) or hidden */ - if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) { - break; - } retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, nu->bp[u].vec, &dist_px_sq, r_loc); } } - else { - /* curve is not visible outside editmode if nurb length less than two */ - if (nu->pntsu > 1) { - if (nu->bezt) { - retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, - is_persp, nu->bezt[u].vec[1], &dist_px_sq, - r_loc); - } - else { - retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, - is_persp, nu->bp[u].vec, &dist_px_sq, - r_loc); - } - } - } - break; } } } @@ -1279,7 +1430,10 @@ static bool snapCurve( if (retval) { *dist_px = sqrtf(dist_px_sq); mul_m4_v3(obmat, r_loc); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + if (r_index) { + /* Does not support index yet. */ + *r_index = -1; + } return true; } return false; @@ -1290,9 +1444,9 @@ static bool snapEmpty( SnapData *snapdata, Object *ob, float obmat[4][4], /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float *UNUSED(r_no)) + float r_loc[3], float *UNUSED(r_no), int *r_index) { bool retval = false; @@ -1308,32 +1462,46 @@ static bool snapEmpty( dist_squared_to_projected_aabb_precalc( &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval); + float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; + transpose_m4_m4(tobmat, obmat); + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP; float dist_px_sq = SQUARE(*dist_px); float co[3]; copy_v3_v3(co, obmat[3]); if (test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, co, &dist_px_sq, r_loc)) { *dist_px = sqrtf(dist_px_sq); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); retval = true; } break; } } - return retval; + if (retval) { + if (r_index) { + /* Does not support index. */ + *r_index = -1; + } + return true; + } + + return false; } static bool snapCamera( const SnapObjectContext *sctx, SnapData *snapdata, Object *object, float obmat[4][4], /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float *UNUSED(r_no)) + float r_loc[3], float *UNUSED(r_no), int *r_index) { Scene *scene = sctx->scene; @@ -1352,6 +1520,12 @@ static bool snapCamera( return retval; } + float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; + transpose_m4_m4(tobmat, obmat); + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + tracking = &clip->tracking; BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat); @@ -1402,7 +1576,8 @@ static bool snapCamera( mul_m4_v3(vertex_obmat, bundle_pos); retval |= test_projected_vert_dist( - &neasrest_precalc, snapdata->depth_range, + &neasrest_precalc, + clip_planes_local, snapdata->clip_plane_len, is_persp, bundle_pos, &dist_px_sq, r_loc); } } @@ -1413,7 +1588,10 @@ static bool snapCamera( if (retval) { *dist_px = sqrtf(dist_px_sq); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + if (r_index) { + /* Does not support index. */ + *r_index = -1; + } return true; } return false; @@ -1423,9 +1601,9 @@ static bool snapMesh( SnapObjectContext *sctx, SnapData *snapdata, Object *ob, Mesh *me, float obmat[4][4], /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float r_no[3]) + float r_loc[3], float r_no[3], int *r_index) { bool retval = false; @@ -1553,15 +1731,8 @@ static bool snapMesh( } } - /* Warning: the depth_max is currently being used only in perspective view. - * It is not correct to limit the maximum depth for elements obtained with nearest - * since this limitation depends on the normal and the size of the occlusion face. - * And more... ray_depth is being confused with Z-depth here... (varies only the precision) */ - const float ray_depth_max_global = *ray_depth + snapdata->depth_range[0]; - Nearest2dUserData neasrest2d = { .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP, - .depth_range = {snapdata->depth_range[0], ray_depth_max_global}, .snap_to = snapdata->snap_to, .userdata = treedata, .get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get, @@ -1576,42 +1747,53 @@ static bool snapMesh( .dist_sq = dist_px_sq, }; + float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; + transpose_m4_m4(tobmat, obmat); + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + if (bvhtree[1]) { /* snap to loose verts */ BLI_bvhtree_find_nearest_projected( bvhtree[1], lpmat, snapdata->win_size, snapdata->mval, - NULL, 0, &nearest, cb_walk_leaf_snap_vert, &neasrest2d); + clip_planes_local, snapdata->clip_plane_len, + &nearest, cb_walk_leaf_snap_vert, &neasrest2d); } if (bvhtree[0]) { /* snap to loose edges */ BLI_bvhtree_find_nearest_projected( bvhtree[0], lpmat, snapdata->win_size, snapdata->mval, - NULL, 0, &nearest, cb_walk_leaf_snap_edge, &neasrest2d); + clip_planes_local, snapdata->clip_plane_len, + &nearest, cb_walk_leaf_snap_edge, &neasrest2d); } if (treedata->tree) { /* snap to looptris */ BLI_bvhtree_find_nearest_projected( treedata->tree, lpmat, snapdata->win_size, snapdata->mval, - NULL, 0, &nearest, cb_walk_leaf_snap_tri, &neasrest2d); + clip_planes_local, snapdata->clip_plane_len, + &nearest, cb_walk_leaf_snap_tri, &neasrest2d); } if (nearest.index != -1) { - float imat[4][4]; - float timat[3][3]; /* transpose inverse matrix for normals */ - invert_m4_m4(imat, obmat); - transpose_m3_m4(timat, imat); + *dist_px = sqrtf(nearest.dist_sq); copy_v3_v3(r_loc, nearest.co); mul_m4_v3(obmat, r_loc); + if (r_no) { + float imat[4][4]; + invert_m4_m4(imat, obmat); + copy_v3_v3(r_no, nearest.no); - mul_m3_v3(timat, r_no); + mul_transposed_mat3_m4_v3(obmat, r_no); normalize_v3(r_no); } - *dist_px = sqrtf(nearest.dist_sq); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + if (r_index) { + *r_index = nearest.index; + } retval = true; } @@ -1623,9 +1805,9 @@ static bool snapEditMesh( SnapObjectContext *sctx, SnapData *snapdata, Object *ob, BMEditMesh *em, float obmat[4][4], /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float r_no[3]) + float r_loc[3], float r_no[3], int *r_index) { bool retval = false; @@ -1713,7 +1895,6 @@ static bool snapEditMesh( Nearest2dUserData neasrest2d = { .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP, - .depth_range = {snapdata->depth_range[0], *ray_depth + snapdata->depth_range[0]}, .snap_to = snapdata->snap_to, .userdata = treedata->em, .get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get, @@ -1736,27 +1917,35 @@ static bool snapEditMesh( BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT); } - float lpmat[4][4]; + float lpmat[4][4], tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; mul_m4_m4m4(lpmat, snapdata->pmat, obmat); + transpose_m4_m4(tobmat, obmat); + + for (int i = snapdata->clip_plane_len; i--;) { + mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]); + } + BLI_bvhtree_find_nearest_projected( treedata->tree, lpmat, snapdata->win_size, snapdata->mval, - NULL, 0, &nearest, cb_walk_leaf, &neasrest2d); + clip_planes_local, snapdata->clip_plane_len, + &nearest, cb_walk_leaf, &neasrest2d); if (nearest.index != -1) { - float imat[4][4]; - float timat[3][3]; /* transpose inverse matrix for normals */ - invert_m4_m4(imat, obmat); - transpose_m3_m4(timat, imat); + *dist_px = sqrtf(nearest.dist_sq); copy_v3_v3(r_loc, nearest.co); mul_m4_v3(obmat, r_loc); if (r_no) { + float imat[4][4]; + invert_m4_m4(imat, obmat); + copy_v3_v3(r_no, nearest.no); - mul_m3_v3(timat, r_no); + mul_transposed_mat3_m4_v3(obmat, r_no); normalize_v3(r_no); } - *dist_px = sqrtf(nearest.dist_sq); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + if (r_index) { + *r_index = nearest.index; + } retval = true; } @@ -1773,9 +1962,9 @@ static bool snapObject( SnapObjectContext *sctx, SnapData *snapdata, Object *ob, float obmat[4][4], bool use_obedit, /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float r_no[3], + float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) { bool retval = false; @@ -1786,45 +1975,45 @@ static bool snapObject( BMEditMesh *em = BKE_editmesh_from_object(ob); retval = snapEditMesh( sctx, snapdata, ob, em, obmat, - ray_depth, dist_px, - r_loc, r_no); + dist_px, + r_loc, r_no, r_index); } else { retval = snapMesh( sctx, snapdata, ob, ob->data, obmat, - ray_depth, dist_px, - r_loc, r_no); + dist_px, + r_loc, r_no, r_index); } break; case OB_ARMATURE: retval = snapArmature( snapdata, - ob, ob->data, obmat, - ray_depth, dist_px, - r_loc, r_no); + ob, obmat, use_obedit, + dist_px, + r_loc, r_no, r_index); break; case OB_CURVE: retval = snapCurve( snapdata, ob, obmat, use_obedit, - ray_depth, dist_px, - r_loc, r_no); + dist_px, + r_loc, r_no, r_index); break; case OB_EMPTY: retval = snapEmpty( snapdata, ob, obmat, - ray_depth, dist_px, - r_loc, r_no); + dist_px, + r_loc, r_no, r_index); break; case OB_CAMERA: retval = snapCamera( sctx, snapdata, ob, obmat, - ray_depth, dist_px, - r_loc, r_no); + dist_px, + r_loc, r_no, r_index); break; } @@ -1845,11 +2034,11 @@ static bool snapObject( struct SnapObjUserData { SnapData *snapdata; /* read/write args */ - float *ray_depth; float *dist_px; /* return args */ float *r_loc; float *r_no; + int *r_index; Object **r_ob; float (*r_obmat)[4]; bool ret; @@ -1862,9 +2051,9 @@ static void sanp_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, flo sctx, dt->snapdata, ob, obmat, is_obedit, /* read/write args */ - dt->ray_depth, dt->dist_px, + dt->dist_px, /* return args */ - dt->r_loc, dt->r_no, + dt->r_loc, dt->r_no, dt->r_index, dt->r_ob, dt->r_obmat); } @@ -1901,18 +2090,18 @@ static bool snapObjectsRay( SnapObjectContext *sctx, SnapData *snapdata, const struct SnapObjectParams *params, /* read/write args */ - float *ray_depth, float *dist_px, + float *dist_px, /* return args */ - float r_loc[3], float r_no[3], + float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) { struct SnapObjUserData data = { .snapdata = snapdata, - .ray_depth = ray_depth, .dist_px = dist_px, .r_loc = r_loc, .r_no = r_no, .r_ob = r_ob, + .r_index = r_index, .r_obmat = r_obmat, .ret = false, }; @@ -2111,53 +2300,25 @@ static bool transform_snap_context_project_view3d_mixed_impl( const float mval[2], float *dist_px, float r_co[3], float r_no[3]) { - float ray_depth = BVH_RAYCAST_DIST_MAX; - bool is_hit = false; - const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE}; BLI_assert(snap_to_flag != 0); BLI_assert((snap_to_flag & ~(1 | 2 | 4)) == 0); - if (params->use_occlusion_test) { - const float dist_px_orig = dist_px ? *dist_px : 0; - for (int i = 2; i >= 0; i--) { - if (snap_to_flag & (1 << i)) { - if (i == 0) { - BLI_assert(dist_px != NULL); - *dist_px = dist_px_orig; - } - if (ED_transform_snap_object_project_view3d( - sctx, - elem_type[i], params, - mval, dist_px, &ray_depth, - r_co, r_no)) - { - /* 0.01 is a random but small value to prioritizing - * the first elements of the loop */ - ray_depth += 0.01f; - is_hit = true; - } - } - } - } - else { - for (int i = 0; i < 3; i++) { - if (snap_to_flag & (1 << i)) { - if (ED_transform_snap_object_project_view3d( - sctx, - elem_type[i], params, - mval, dist_px, &ray_depth, - r_co, r_no)) - { - is_hit = true; - break; - } + for (int i = 0; i < 3; i++) { + if (snap_to_flag & (1 << i)) { + if (ED_transform_snap_object_project_view3d( + sctx, + elem_type[i], params, + mval, dist_px, + r_co, r_no)) + { + return true; } } } - return is_hit; + return false; } /** @@ -2191,55 +2352,98 @@ bool ED_transform_snap_object_project_view3d_ex( const unsigned short snap_to, const struct SnapObjectParams *params, const float mval[2], float *dist_px, - float *ray_depth, float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) { - const ARegion *ar = sctx->v3d_data.ar; - const RegionView3D *rv3d = ar->regiondata; + float loc[3], no[3], obmat[4][4]; + Object *ob = NULL; - float ray_origin[3], ray_end[3], ray_start[3], ray_normal[3], depth_range[2]; - - ED_view3d_win_to_origin(ar, mval, ray_origin); - ED_view3d_win_to_vector(ar, mval, ray_normal); + int index_fallback; + if (r_index == NULL) { + r_index = &index_fallback; + } - ED_view3d_clip_range_get( - sctx->depsgraph, - sctx->v3d_data.v3d, sctx->v3d_data.ar->regiondata, - &depth_range[0], &depth_range[1], false); + bool has_hit = false, retval = false; + const ARegion *ar = sctx->v3d_data.ar; + const RegionView3D *rv3d = ar->regiondata; - madd_v3_v3v3fl(ray_start, ray_origin, ray_normal, depth_range[0]); - madd_v3_v3v3fl(ray_end, ray_origin, ray_normal, depth_range[1]); + if (snap_to == SCE_SNAP_MODE_FACE || params->use_occlusion_test) { + float ray_start[3], ray_normal[3]; - if (!ED_view3d_clip_segment(rv3d, ray_start, ray_end)) { - return false; - } + if (!ED_view3d_win_to_ray_ex( + sctx->depsgraph, + sctx->v3d_data.ar, sctx->v3d_data.v3d, + mval, NULL, ray_normal, ray_start, true)) + { + return false; + } - float ray_depth_fallback; - if (ray_depth == NULL) { - ray_depth_fallback = BVH_RAYCAST_DIST_MAX; - ray_depth = &ray_depth_fallback; - } + float dummy_ray_depth = BVH_RAYCAST_DIST_MAX; - if (snap_to == SCE_SNAP_MODE_FACE) { - return raycastObjects( + has_hit = raycastObjects( sctx, params, ray_start, ray_normal, - ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL); + &dummy_ray_depth, loc, no, + r_index, &ob, obmat, NULL); + + retval = has_hit && (snap_to == SCE_SNAP_MODE_FACE); } - else { + + if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) { SnapData snapdata; - const enum eViewProj view_proj = rv3d->is_persp ? - VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO; - snap_data_set( - &snapdata, ar, snap_to, view_proj, mval, - ray_start, ray_normal, depth_range); + copy_m4_m4(snapdata.pmat, rv3d->persmat); + snapdata.win_size[0] = ar->winx; + snapdata.win_size[1] = ar->winy; + copy_v2_v2(snapdata.mval, mval); + snapdata.snap_to = snap_to; + snapdata.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO; + + planes_from_projmat( + snapdata.pmat, + NULL, NULL, NULL, NULL, + snapdata.clip_plane[0], snapdata.clip_plane[1]); + + snapdata.clip_plane_len = 2; + + if (has_hit) { + /* Compute the new clip_pane but do not add it yet. */ + float new_clipplane[4]; + plane_from_point_normal_v3(new_clipplane, loc, no); + + /* Try to snap only to the polygon. */ + retval |= snapMeshPolygon( + sctx, &snapdata, ob, obmat, + dist_px, loc, no, r_index); + + /* Add the new clip plane to the beginning of the list. */ + for (int i = snapdata.clip_plane_len; i != 0; i--) { + copy_v4_v4(snapdata.clip_plane[i], snapdata.clip_plane[i - 1]); + } + copy_v4_v4(snapdata.clip_plane[0], new_clipplane); + snapdata.clip_plane_len++; + } - return snapObjectsRay( + retval |= snapObjectsRay( sctx, &snapdata, params, - ray_depth, dist_px, r_loc, r_no, r_ob, r_obmat); + dist_px, loc, no, r_index, &ob, obmat); + } + + if (retval) { + copy_v3_v3(r_loc, loc); + if (r_no) { + copy_v3_v3(r_no, no); + } + if (r_ob) { + *r_ob = ob; + } + if (r_obmat) { + copy_m4_m4(r_obmat, obmat); + } + return true; } + + return false; } bool ED_transform_snap_object_project_view3d( @@ -2247,7 +2451,6 @@ bool ED_transform_snap_object_project_view3d( const unsigned short snap_to, const struct SnapObjectParams *params, const float mval[2], float *dist_px, - float *ray_depth, float r_loc[3], float r_no[3]) { return ED_transform_snap_object_project_view3d_ex( @@ -2255,7 +2458,6 @@ bool ED_transform_snap_object_project_view3d( snap_to, params, mval, dist_px, - ray_depth, r_loc, r_no, NULL, NULL, NULL); } |