/** * Given an array of faces, recalculate their normals. * this functions assumes all faces in the array are connected by edges. * * \param bm: * \param faces: Array of connected faces. * \param faces_len: Length of \a faces * \param oflag: Flag to check before doing the actual face flipping. */ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int faces_len, const short oflag) { int i, f_start_index; const short oflag_flip = oflag | FACE_FLIP; bool is_flip; BMFace *f; BLI_LINKSTACK_DECLARE(fstack, BMFace *); f_start_index = recalc_face_normals_find_index(bm, faces, faces_len, &is_flip); if (is_flip) { BMO_face_flag_enable(bm, faces[f_start_index], FACE_FLIP); } /* now that we've found our starting face, make all connected faces * have the same winding. this is done recursively, using a manual * stack (if we use simple function recursion, we'd end up overloading * the stack on large meshes). */ BLI_LINKSTACK_INIT(fstack); BLI_LINKSTACK_PUSH(fstack, faces[f_start_index]); BMO_face_flag_enable(bm, faces[f_start_index], FACE_TEMP); while ((f = BLI_LINKSTACK_POP(fstack))) { const bool flip_state = BMO_face_flag_test_bool(bm, f, FACE_FLIP); BMLoop *l_iter, *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { BMLoop *l_other = l_iter->radial_next; if ((l_other != l_iter) && bmo_recalc_normal_loop_filter_cb(l_iter, NULL)) { if (!BMO_face_flag_test(bm, l_other->f, FACE_TEMP)) { BMO_face_flag_enable(bm, l_other->f, FACE_TEMP); BMO_face_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state); BLI_LINKSTACK_PUSH(fstack, l_other->f); } } } while ((l_iter = l_iter->next) != l_first); } BLI_LINKSTACK_FREE(fstack); /* apply flipping to oflag'd faces */ for (i = 0; i < faces_len; i++) { if (BMO_face_flag_test(bm, faces[i], oflag_flip) == oflag_flip) { BM_face_normal_flip(bm, faces[i]); } BMO_face_flag_disable(bm, faces[i], FACE_TEMP); } }
/** * <pre> * v5 * / \ * s v6/---\ v4 s * / \ / \ * sv7/---v---\ v3 s * / \/ \/ \ * v8--v0--v1--v2 * s s * </pre> */ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, const SubDParams *params) { BMFace *f_new; BMEdge *e, *e_new, e_tmp; BMVert ***lines, *v, v1_tmp, v2_tmp; void *stackarr[1]; int i, j, a, b, numcuts = params->numcuts; /* number of verts in each lin */ lines = MEM_callocN(sizeof(void *) * (numcuts + 2), "triangle vert table"); lines[0] = (BMVert **)stackarr; lines[0][0] = verts[numcuts * 2 + 1]; lines[numcuts + 1] = MEM_callocN(sizeof(void *) * (numcuts + 2), "triangle vert table 2"); for (i = 0; i < numcuts; i++) { lines[numcuts + 1][i + 1] = verts[i]; } lines[numcuts + 1][0] = verts[numcuts * 3 + 2]; lines[numcuts + 1][numcuts + 1] = verts[numcuts]; for (i = 0; i < numcuts; i++) { lines[i + 1] = MEM_callocN(sizeof(void *) * (2 + i), "triangle vert table row"); a = numcuts * 2 + 2 + i; b = numcuts + numcuts - i; e = connect_smallest_face(bm, verts[a], verts[b], &f_new); if (!e) { goto cleanup; } BMO_edge_flag_enable(bm, e, ELE_INNER); BMO_face_flag_enable(bm, f_new, ELE_INNER); lines[i + 1][0] = verts[a]; lines[i + 1][i + 1] = verts[b]; e_tmp = *e; v1_tmp = *verts[a]; v2_tmp = *verts[b]; e_tmp.v1 = &v1_tmp; e_tmp.v2 = &v2_tmp; for (j = 0; j < i; j++) { v = subdivide_edge_num(bm, e, &e_tmp, j, i, params, verts[a], verts[b], &e_new); lines[i + 1][j + 1] = v; BMO_edge_flag_enable(bm, e_new, ELE_INNER); } } /** * <pre> * v5 * / \ * s v6/---\ v4 s * / \ / \ * sv7/---v---\ v3 s * / \/ \/ \ * v8--v0--v1--v2 * s s * </pre> */ for (i = 1; i <= numcuts; i++) { for (j = 0; j < i; j++) { e = connect_smallest_face(bm, lines[i][j], lines[i + 1][j + 1], &f_new); BMO_edge_flag_enable(bm, e, ELE_INNER); BMO_face_flag_enable(bm, f_new, ELE_INNER); e = connect_smallest_face(bm, lines[i][j + 1], lines[i + 1][j + 1], &f_new); BMO_edge_flag_enable(bm, e, ELE_INNER); BMO_face_flag_enable(bm, f_new, ELE_INNER); } } cleanup: for (i = 1; i < numcuts + 2; i++) { if (lines[i]) { MEM_freeN(lines[i]); } } MEM_freeN(lines); }
/** * \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 }
/** * <pre> * v8--v7-v6--v5 * | s | * |v9 s s|v4 * first line | | last line * |v10s s s|v3 * v11-v0--v1-v2 * * it goes from bottom up * </pre> */ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, const SubDParams *params) { BMFace *f_new; BMVert *v, *v1, *v2; BMEdge *e, *e_new, e_tmp; BMVert **lines; int numcuts = params->numcuts; int i, j, a, b, s = numcuts + 2 /* , totv = numcuts * 4 + 4 */; lines = MEM_callocN(sizeof(BMVert *) * (numcuts + 2) * (numcuts + 2), "q_4edge_split"); /* build a 2-dimensional array of verts, * containing every vert (and all new ones) * in the face */ /* first line */ for (i = 0; i < numcuts + 2; i++) { lines[i] = verts[numcuts * 3 + 2 + (numcuts - i + 1)]; } /* last line */ for (i = 0; i < numcuts + 2; i++) { lines[(s - 1) * s + i] = verts[numcuts + i]; } /* first and last members of middle lines */ for (i = 0; i < numcuts; i++) { a = i; b = numcuts + 1 + numcuts + 1 + (numcuts - i - 1); e = connect_smallest_face(bm, verts[a], verts[b], &f_new); if (!e) { continue; } BMO_edge_flag_enable(bm, e, ELE_INNER); BMO_face_flag_enable(bm, f_new, ELE_INNER); v1 = lines[(i + 1) * s] = verts[a]; v2 = lines[(i + 1) * s + s - 1] = verts[b]; e_tmp = *e; for (a = 0; a < numcuts; a++) { v = subdivide_edge_num(bm, e, &e_tmp, a, numcuts, params, v1, v2, &e_new); BMESH_ASSERT(v != NULL); BMO_edge_flag_enable(bm, e_new, ELE_INNER); lines[(i + 1) * s + a + 1] = v; } } for (i = 1; i < numcuts + 2; i++) { for (j = 1; j <= numcuts; j++) { a = i * s + j; b = (i - 1) * s + j; e = connect_smallest_face(bm, lines[a], lines[b], &f_new); if (!e) { continue; } BMO_edge_flag_enable(bm, e, ELE_INNER); BMO_face_flag_enable(bm, f_new, ELE_INNER); } } MEM_freeN(lines); }