/** * Return the coords from a triangle. */ static void bmbvh_tri_from_face(const float *cos[3], const BMLoop **ltri, const float (*cos_cage)[3]) { if (cos_cage == NULL) { cos[0] = ltri[0]->v->co; cos[1] = ltri[1]->v->co; cos[2] = ltri[2]->v->co; } else { cos[0] = cos_cage[BM_elem_index_get(ltri[0]->v)]; cos[1] = cos_cage[BM_elem_index_get(ltri[1]->v)]; cos[2] = cos_cage[BM_elem_index_get(ltri[2]->v)]; } }
BLI_INLINE bool edge_in_array(const BMEdge *e, const BMEdge **edge_array, const int edge_array_len) { const int index = BM_elem_index_get(e); return ((index >= 0) && (index < edge_array_len) && (e == edge_array[index])); }
static void erot_state_ex(const BMEdge *e, int v_index[2], int f_index[2]) { BLI_assert(BM_edge_is_manifold(e)); BLI_assert(BM_vert_in_edge(e, e->l->prev->v) == false); BLI_assert(BM_vert_in_edge(e, e->l->radial_next->prev->v) == false); /* verts of the edge */ v_index[0] = BM_elem_index_get(e->v1); v_index[1] = BM_elem_index_get(e->v2); EDGE_ORD(v_index[0], v_index[1]); /* verts of each of the 2 faces attached to this edge * (that are not apart of this edge) */ f_index[0] = BM_elem_index_get(e->l->prev->v); f_index[1] = BM_elem_index_get(e->l->radial_next->prev->v); EDGE_ORD(f_index[0], f_index[1]); }
/* helper function for 'BM_mesh_copy' */ static BMFace *bm_mesh_copy_new_face( BMesh *bm_new, BMesh *bm_old, BMVert **vtable, BMEdge **etable, BMFace *f) { BMLoop **loops = BLI_array_alloca(loops, f->len); BMVert **verts = BLI_array_alloca(verts, f->len); BMEdge **edges = BLI_array_alloca(edges, f->len); BMFace *f_new; BMLoop *l_iter, *l_first; int j; j = 0; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { loops[j] = l_iter; verts[j] = vtable[BM_elem_index_get(l_iter->v)]; edges[j] = etable[BM_elem_index_get(l_iter->e)]; j++; } while ((l_iter = l_iter->next) != l_first); f_new = BM_face_create(bm_new, verts, edges, f->len, NULL, BM_CREATE_SKIP_CD); if (UNLIKELY(f_new == NULL)) { return NULL; } /* use totface in case adding some faces fails */ BM_elem_index_set(f_new, (bm_new->totface - 1)); /* set_inline */ BM_elem_attrs_copy_ex(bm_old, bm_new, f, f_new, 0xff, 0x0); f_new->head.hflag = f->head.hflag; /* low level! don't do this for normal api use */ j = 0; l_iter = l_first = BM_FACE_FIRST_LOOP(f_new); do { BM_elem_attrs_copy(bm_old, bm_new, loops[j], l_iter); j++; } while ((l_iter = l_iter->next) != l_first); return f_new; }
static void face_edges_add( struct ISectState *s, const int f_index, BMEdge *e, const bool use_test) { void *f_index_key = SET_INT_IN_POINTER(f_index); BLI_assert(e->head.htype == BM_EDGE); BLI_assert(BM_edge_in_face(e, s->bm->ftable[f_index]) == false); BLI_assert(BM_elem_index_get(s->bm->ftable[f_index]) == f_index); ghash_insert_link(s->face_edges, f_index_key, e, use_test, s->mem_arena); }
static void face_edges_split( BMesh *bm, BMFace *f, struct LinkBase *e_ls_base, bool use_island_connect, MemArena *mem_arena_edgenet) { unsigned int i; unsigned int edge_arr_len = e_ls_base->list_len; BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len); LinkNode *node; BLI_assert(f->head.htype == BM_FACE); for (i = 0, node = e_ls_base->list; i < e_ls_base->list_len; i++, node = node->next) { edge_arr[i] = node->link; } BLI_assert(node == NULL); #ifdef USE_DUMP printf("# %s: %d %u\n", __func__, BM_elem_index_get(f), e_ls_base->list_len); #endif #ifdef USE_NET_ISLAND_CONNECT if (use_island_connect) { unsigned int edge_arr_holes_len; BMEdge **edge_arr_holes; if (BM_face_split_edgenet_connect_islands( bm, f, edge_arr, edge_arr_len, false, mem_arena_edgenet, &edge_arr_holes, &edge_arr_holes_len)) { edge_arr_len = edge_arr_holes_len; edge_arr = edge_arr_holes; /* owned by the arena */ } } #else UNUSED_VARS(use_island_connect, mem_arena_edgenet); #endif BM_face_split_edgenet(bm, f, edge_arr, (int)edge_arr_len, NULL, NULL); }
/* recalc an edge in the heap (surrounding geometry has changed) */ static void bm_edge_update_beauty_cost_single( BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr, /* only for testing the edge is in the array */ const BMEdge **edge_array, const int edge_array_len, const short flag, const short method) { if (edge_in_array(e, edge_array, edge_array_len)) { const int i = BM_elem_index_get(e); GSet *e_state_set = edge_state_arr[i]; if (eheap_table[i]) { BLI_heap_remove(eheap, eheap_table[i]); eheap_table[i] = NULL; } /* check if we can add it back */ BLI_assert(BM_edge_is_manifold(e) == true); /* check we're not moving back into a state we have been in before */ if (e_state_set != NULL) { EdRotState e_state_alt; erot_state_alternate(e, &e_state_alt); if (BLI_gset_haskey(e_state_set, (void *)&e_state_alt)) { // printf(" skipping, we already have this state\n"); return; } } { /* recalculate edge */ const float cost = bm_edge_calc_rotate_beauty(e, flag, method); if (cost < 0.0f) { eheap_table[i] = BLI_heap_insert(eheap, cost, e); } else { eheap_table[i] = NULL; } } } }
static void face_edges_split( BMesh *bm, BMFace *f, struct LinkBase *e_ls_base) { unsigned int i; BMEdge **edge_arr = BLI_array_alloca(edge_arr, e_ls_base->list_len); LinkNode *node; BLI_assert(f->head.htype == BM_FACE); for (i = 0, node = e_ls_base->list; i < e_ls_base->list_len; i++, node = node->next) { edge_arr[i] = node->link; } BLI_assert(node == NULL); #ifdef USE_DUMP printf("# %s: %d %u\n", __func__, BM_elem_index_get(f), e_ls_base->list_len); #endif BM_face_split_edgenet(bm, f, edge_arr, (int)e_ls_base->list_len, NULL, NULL); }
BMBVHTree *BKE_bmbvh_new_ex( BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag, const float (*cos_cage)[3], const bool cos_cage_free, bool (*test_fn)(BMFace *, void *user_data), void *user_data) { /* could become argument */ const float epsilon = FLT_EPSILON * 2.0f; BMBVHTree *bmtree = MEM_callocN(sizeof(*bmtree), "BMBVHTree"); float cos[3][3]; int i; int tottri; /* avoid testing every tri */ BMFace *f_test, *f_test_prev; bool test_fn_ret; /* BKE_editmesh_tessface_calc() must be called already */ BLI_assert(looptris_tot != 0 || bm->totface == 0); if (cos_cage) { BM_mesh_elem_index_ensure(bm, BM_VERT); } bmtree->looptris = looptris; bmtree->looptris_tot = looptris_tot; bmtree->bm = bm; bmtree->cos_cage = cos_cage; bmtree->cos_cage_free = cos_cage_free; bmtree->flag = flag; if (test_fn) { /* callback must do... */ BLI_assert(!(flag & (BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN))); f_test_prev = NULL; test_fn_ret = false; tottri = 0; for (i = 0; i < looptris_tot; i++) { f_test = looptris[i][0]->f; if (f_test != f_test_prev) { test_fn_ret = test_fn(f_test, user_data); f_test_prev = f_test; } if (test_fn_ret) { tottri++; } } } else { tottri = looptris_tot; } bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8); f_test_prev = NULL; test_fn_ret = false; for (i = 0; i < looptris_tot; i++) { if (test_fn) { /* note, the arrays wont align now! take care */ f_test = looptris[i][0]->f; if (f_test != f_test_prev) { test_fn_ret = test_fn(f_test, user_data); f_test_prev = f_test; } if (!test_fn_ret) { continue; } } if (cos_cage) { copy_v3_v3(cos[0], cos_cage[BM_elem_index_get(looptris[i][0]->v)]); copy_v3_v3(cos[1], cos_cage[BM_elem_index_get(looptris[i][1]->v)]); copy_v3_v3(cos[2], cos_cage[BM_elem_index_get(looptris[i][2]->v)]); } else { copy_v3_v3(cos[0], looptris[i][0]->v->co); copy_v3_v3(cos[1], looptris[i][1]->v->co); copy_v3_v3(cos[2], looptris[i][2]->v->co); } BLI_bvhtree_insert(bmtree->tree, i, (float *)cos, 3); } BLI_bvhtree_balance(bmtree->tree); return bmtree; }
static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int mval[2]) { MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz; struct { Object *ob; BMElem *ele; float dist; int base_index; } best = { .dist = ED_view3d_select_dist_px(), }; struct { int base_index; int vert_index; int edge_index; int face_index; } prev = { .base_index = gz_ele->base_index, .vert_index = gz_ele->vert_index, .edge_index = gz_ele->edge_index, .face_index = gz_ele->face_index, }; { ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); if (((gz_ele->bases)) == NULL || (gz_ele->bases[0] != view_layer->basact)) { MEM_SAFE_FREE(gz_ele->bases); gz_ele->bases = BKE_view_layer_array_from_bases_in_edit_mode( view_layer, v3d, &gz_ele->bases_len); } } ViewContext vc; em_setup_viewcontext(C, &vc); copy_v2_v2_int(vc.mval, mval); { /* TODO: support faces. */ int base_index = -1; BMVert *eve_test; BMEdge *eed_test; if (EDBM_unified_findnearest_from_raycast(&vc, gz_ele->bases, gz_ele->bases_len, true, &base_index, &eve_test, &eed_test, NULL)) { Base *base = gz_ele->bases[base_index]; best.ob = base->object; if (eve_test) { best.ele = (BMElem *)eve_test; } else if (eed_test) { best.ele = (BMElem *)eed_test; } else { BLI_assert(0); } best.base_index = base_index; /* Check above should never fail, if it does it's an internal error. */ BLI_assert(best.base_index != -1); } } BMesh *bm = NULL; gz_ele->base_index = -1; gz_ele->vert_index = -1; gz_ele->edge_index = -1; gz_ele->face_index = -1; if (best.ele) { gz_ele->base_index = best.base_index; bm = BKE_editmesh_from_object(gz_ele->bases[gz_ele->base_index]->object)->bm; BM_mesh_elem_index_ensure(bm, best.ele->head.htype); if (best.ele->head.htype == BM_VERT) { gz_ele->vert_index = BM_elem_index_get(best.ele); } else if (best.ele->head.htype == BM_EDGE) { gz_ele->edge_index = BM_elem_index_get(best.ele); } else if (best.ele->head.htype == BM_FACE) { gz_ele->face_index = BM_elem_index_get(best.ele); } } if ((prev.base_index == gz_ele->base_index) && (prev.vert_index == gz_ele->vert_index) && (prev.edge_index == gz_ele->edge_index) && (prev.face_index == gz_ele->face_index)) { /* pass (only recalculate on change) */ } else { if (best.ele) { const float(*coords)[3] = NULL; { Object *ob = gz_ele->bases[gz_ele->base_index]->object; Depsgraph *depsgraph = CTX_data_depsgraph(C); Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data); if (me_eval->runtime.edit_data) { coords = me_eval->runtime.edit_data->vertexCos; } } EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords); } else { EDBM_preselect_elem_clear(gz_ele->psel); } RNA_int_set(gz->ptr, "object_index", gz_ele->base_index); RNA_int_set(gz->ptr, "vert_index", gz_ele->vert_index); RNA_int_set(gz->ptr, "edge_index", gz_ele->edge_index); RNA_int_set(gz->ptr, "face_index", gz_ele->face_index); ARegion *ar = CTX_wm_region(C); ED_region_tag_redraw(ar); } // return best.eed ? 0 : -1; return -1; } static void gizmo_preselect_elem_setup(wmGizmo *gz) { MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz; if (gz_ele->psel == NULL) { gz_ele->psel = EDBM_preselect_elem_create(); } gz_ele->base_index = -1; }
static int gizmo_preselect_edgering_test_select(bContext *C, wmGizmo *gz, const int mval[2]) { MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz; struct { Object *ob; BMEdge *eed; float dist; int base_index; } best = { .dist = ED_view3d_select_dist_px(), }; struct { int base_index; int edge_index; } prev = { .base_index = gz_ring->base_index, .edge_index = gz_ring->edge_index, }; { ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); if (((gz_ring->bases)) == NULL || (gz_ring->bases[0] != view_layer->basact)) { MEM_SAFE_FREE(gz_ring->bases); gz_ring->bases = BKE_view_layer_array_from_bases_in_edit_mode( view_layer, v3d, &gz_ring->bases_len); } } ViewContext vc; em_setup_viewcontext(C, &vc); copy_v2_v2_int(vc.mval, mval); uint base_index; BMEdge *eed_test = EDBM_edge_find_nearest_ex( &vc, &best.dist, NULL, false, false, NULL, gz_ring->bases, gz_ring->bases_len, &base_index); if (eed_test) { best.ob = gz_ring->bases[base_index]->object; best.eed = eed_test; best.base_index = base_index; } BMesh *bm = NULL; if (best.eed) { gz_ring->base_index = best.base_index; bm = BKE_editmesh_from_object(gz_ring->bases[gz_ring->base_index]->object)->bm; BM_mesh_elem_index_ensure(bm, BM_EDGE); gz_ring->edge_index = BM_elem_index_get(best.eed); } else { gz_ring->base_index = -1; gz_ring->edge_index = -1; } if ((prev.base_index == gz_ring->base_index) && (prev.edge_index == gz_ring->edge_index)) { /* pass (only recalculate on change) */ } else { if (best.eed) { const float(*coords)[3] = NULL; { Object *ob = gz_ring->bases[gz_ring->base_index]->object; Depsgraph *depsgraph = CTX_data_depsgraph(C); Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data); if (me_eval->runtime.edit_data) { coords = me_eval->runtime.edit_data->vertexCos; } } EDBM_preselect_edgering_update_from_edge(gz_ring->psel, bm, best.eed, 1, coords); } else { EDBM_preselect_edgering_clear(gz_ring->psel); } RNA_int_set(gz->ptr, "object_index", gz_ring->base_index); RNA_int_set(gz->ptr, "edge_index", gz_ring->edge_index); ARegion *ar = CTX_wm_region(C); ED_region_tag_redraw(ar); } // return best.eed ? 0 : -1; return -1; } static void gizmo_preselect_edgering_setup(wmGizmo *gz) { MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz; if (gz_ring->psel == NULL) { gz_ring->psel = EDBM_preselect_edgering_create(); } gz_ring->base_index = -1; }
BMBVHTree *BKE_bmbvh_new(BMEditMesh *em, int flag, const float (*cos_cage)[3], const bool cos_cage_free) { /* could become argument */ const float epsilon = FLT_EPSILON * 2.0f; struct BMLoop *(*looptris)[3] = em->looptris; BMBVHTree *bmtree = MEM_callocN(sizeof(*bmtree), "BMBVHTree"); float cos[3][3]; int i; int tottri; /* BKE_editmesh_tessface_calc() must be called already */ BLI_assert(em->tottri != 0 || em->bm->totface == 0); if (cos_cage) { BM_mesh_elem_index_ensure(em->bm, BM_VERT); } bmtree->em = em; bmtree->bm = em->bm; bmtree->cos_cage = cos_cage; bmtree->cos_cage_free = cos_cage_free; bmtree->flag = flag; if (flag & (BMBVH_RESPECT_SELECT)) { tottri = 0; for (i = 0; i < em->tottri; i++) { if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_SELECT)) { tottri++; } } } else if (flag & (BMBVH_RESPECT_HIDDEN)) { tottri = 0; for (i = 0; i < em->tottri; i++) { if (!BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) { tottri++; } } } else { tottri = em->tottri; } bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8); for (i = 0; i < em->tottri; i++) { if (flag & BMBVH_RESPECT_SELECT) { /* note, the arrays wont align now! take care */ if (!BM_elem_flag_test(em->looptris[i][0]->f, BM_ELEM_SELECT)) { continue; } } else if (flag & BMBVH_RESPECT_HIDDEN) { /* note, the arrays wont align now! take care */ if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) { continue; } } if (cos_cage) { copy_v3_v3(cos[0], cos_cage[BM_elem_index_get(looptris[i][0]->v)]); copy_v3_v3(cos[1], cos_cage[BM_elem_index_get(looptris[i][1]->v)]); copy_v3_v3(cos[2], cos_cage[BM_elem_index_get(looptris[i][2]->v)]); } else { copy_v3_v3(cos[0], looptris[i][0]->v->co); copy_v3_v3(cos[1], looptris[i][1]->v->co); copy_v3_v3(cos[2], looptris[i][2]->v->co); } BLI_bvhtree_insert(bmtree->tree, i, (float *)cos, 3); } BLI_bvhtree_balance(bmtree->tree); return bmtree; }
/** * \note This function sets the edge indices to invalid values. */ void BM_mesh_beautify_fill( BMesh *bm, BMEdge **edge_array, const int edge_array_len, const short flag, const short method, const short oflag_edge, const short oflag_face) { Heap *eheap; /* edge heap */ HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */ GSet **edge_state_arr = MEM_callocN((size_t)edge_array_len * sizeof(GSet *), __func__); BLI_mempool *edge_state_pool = BLI_mempool_create(sizeof(EdRotState), 0, 512, BLI_MEMPOOL_NOP); int i; #ifdef DEBUG_TIME TIMEIT_START(beautify_fill); #endif eheap = BLI_heap_new_ex((uint)edge_array_len); eheap_table = MEM_mallocN(sizeof(HeapNode *) * (size_t)edge_array_len, __func__); /* build heap */ for (i = 0; i < edge_array_len; i++) { BMEdge *e = edge_array[i]; const float cost = bm_edge_calc_rotate_beauty(e, flag, method); if (cost < 0.0f) { eheap_table[i] = BLI_heap_insert(eheap, cost, e); } else { eheap_table[i] = NULL; } BM_elem_index_set(e, i); /* set_dirty */ } bm->elem_index_dirty |= BM_EDGE; while (BLI_heap_is_empty(eheap) == false) { BMEdge *e = BLI_heap_popmin(eheap); i = BM_elem_index_get(e); eheap_table[i] = NULL; BLI_assert(BM_edge_face_count_is_equal(e, 2)); e = BM_edge_rotate(bm, e, false, BM_EDGEROT_CHECK_EXISTS); BLI_assert(e == NULL || BM_edge_face_count_is_equal(e, 2)); if (LIKELY(e)) { GSet *e_state_set = edge_state_arr[i]; /* add the new state into the set so we don't move into this state again * note: we could add the previous state too but this isn't essential) * for avoiding eternal loops */ EdRotState *e_state = BLI_mempool_alloc(edge_state_pool); erot_state_current(e, e_state); if (UNLIKELY(e_state_set == NULL)) { edge_state_arr[i] = e_state_set = erot_gset_new(); /* store previous state */ } BLI_assert(BLI_gset_haskey(e_state_set, (void *)e_state) == false); BLI_gset_insert(e_state_set, e_state); // printf(" %d -> %d, %d\n", i, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2)); /* maintain the index array */ edge_array[i] = e; BM_elem_index_set(e, i); /* recalculate faces connected on the heap */ bm_edge_update_beauty_cost(e, eheap, eheap_table, edge_state_arr, (const BMEdge **)edge_array, edge_array_len, flag, method); /* update flags */ if (oflag_edge) { BMO_edge_flag_enable(bm, e, oflag_edge); } if (oflag_face) { BMO_face_flag_enable(bm, e->l->f, oflag_face); BMO_face_flag_enable(bm, e->l->radial_next->f, oflag_face); } } } BLI_heap_free(eheap, NULL); MEM_freeN(eheap_table); for (i = 0; i < edge_array_len; i++) { if (edge_state_arr[i]) { BLI_gset_free(edge_state_arr[i], NULL); } } MEM_freeN(edge_state_arr); BLI_mempool_destroy(edge_state_pool); #ifdef DEBUG_TIME TIMEIT_END(beautify_fill); #endif }