diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2013-04-06 17:24:34 +0400 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2013-04-06 17:24:34 +0400 |
commit | acfc0ea5111bcab5ea5795187d08b2f6ec5addaa (patch) | |
tree | d9fb7e477ac551859ca95c1f0482eca8b3af1077 /source/blender/bmesh | |
parent | 72d0cc1f6123900f5593cd0fe428568f5aa7f682 (diff) | |
parent | 2ed2226ee753cc6a7a19806d99772efa61af897f (diff) |
svn merge ^/trunk/blender -r55815:55840
Diffstat (limited to 'source/blender/bmesh')
-rw-r--r-- | source/blender/bmesh/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_interp.c | 6 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_opdefines.c | 59 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_operator_api.h | 2 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_operators.c | 25 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_operators.h | 7 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_operators_private.h | 4 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_polygon.c | 28 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_polygon.h | 1 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_inset.c | 227 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_join_triangles.c | 4 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_poke.c | 141 |
12 files changed, 481 insertions, 24 deletions
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index fcf804c8f4f..472f7d2d8f0 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -54,6 +54,7 @@ set(SRC operators/bmo_join_triangles.c operators/bmo_mesh_conv.c operators/bmo_mirror.c + operators/bmo_poke.c operators/bmo_primitive.c operators/bmo_removedoubles.c operators/bmo_similar.c diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index d0ab0ea5d60..6edbae0831e 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -36,12 +36,12 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_customdata.h" -#include "BKE_multires.h" - #include "BLI_array.h" #include "BLI_math.h" +#include "BKE_customdata.h" +#include "BKE_multires.h" + #include "bmesh.h" #include "intern/bmesh_private.h" diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 7583332c4db..a84958f6827 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1500,12 +1500,34 @@ static BMOpDefine bmo_solidify_def = { }; /* - * Face Inset. + * Face Inset (Individual). * - * Inset or outset faces. + * Insets individual faces. */ -static BMOpDefine bmo_inset_def = { - "inset", +static BMOpDefine bmo_inset_individual_def = { + "inset_individual", + /* slots_in */ + {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ + {"thickness", BMO_OP_SLOT_FLT}, + {"depth", BMO_OP_SLOT_FLT}, + {"use_even_offset", BMO_OP_SLOT_BOOL}, + {{'\0'}}, + }, + /* slots_out */ + {{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* output faces */ + {{'\0'}}, + }, + bmo_inset_individual_exec, + 0 +}; + +/* + * Face Inset (Regions). + * + * Inset or outset face regions. + */ +static BMOpDefine bmo_inset_region_def = { + "inset_region", /* slots_in */ {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ {"use_boundary", BMO_OP_SLOT_BOOL}, @@ -1520,7 +1542,7 @@ static BMOpDefine bmo_inset_def = { {{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* output faces */ {{'\0'}}, }, - bmo_inset_exec, + bmo_inset_region_exec, 0 }; @@ -1549,6 +1571,29 @@ static BMOpDefine bmo_wireframe_def = { 0 }; +/* + * Pokes a face. + * + * Splits a face into a triangle fan. + */ +static BMOpDefine bmo_poke_def = { + "poke", + /* slots_in */ + {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ + {"offset", BMO_OP_SLOT_FLT}, /* center vertex offset along normal */ + {"center_mode", BMO_OP_SLOT_INT}, /* calculation mode for center vertex */ + {"use_relative_offset", BMO_OP_SLOT_BOOL}, /* apply offset */ + {{'\0'}}, + }, + /* slots_out */ + {{"verts.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* output verts */ + {"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* output faces */ + {{'\0'}}, + }, + bmo_poke_exec, + 0 +}; + #ifdef WITH_BULLET /* * Convex Hull @@ -1647,13 +1692,15 @@ const BMOpDefine *bmo_opdefines[] = { &bmo_extrude_face_region_def, &bmo_extrude_vert_indiv_def, &bmo_find_doubles_def, - &bmo_inset_def, + &bmo_inset_individual_def, + &bmo_inset_region_def, &bmo_join_triangles_def, &bmo_mesh_to_bmesh_def, &bmo_mirror_def, &bmo_object_load_bmesh_def, &bmo_pointmerge_def, &bmo_pointmerge_facedata_def, + &bmo_poke_def, &bmo_recalc_face_normals_def, &bmo_region_extend_def, &bmo_remove_doubles_def, diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h index 180bc53c2e3..c72accbc605 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api.h +++ b/source/blender/bmesh/intern/bmesh_operator_api.h @@ -482,6 +482,8 @@ typedef struct BMOElemMapping { extern const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES]; +int BMO_opcode_from_opname(const char *opname); + #ifdef __cplusplus } #endif diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c index a358623834f..1d20f94c51c 100644 --- a/source/blender/bmesh/intern/bmesh_operators.c +++ b/source/blender/bmesh/intern/bmesh_operators.c @@ -47,7 +47,6 @@ static void bmo_flag_layer_free(BMesh *bm); static void bmo_flag_layer_clear(BMesh *bm); static int bmo_name_to_slotcode(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier); static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier); -static int bmo_opname_to_opcode(const char *opname); static const char *bmo_error_messages[] = { NULL, @@ -145,7 +144,7 @@ static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args */ void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname) { - int opcode = bmo_opname_to_opcode(opname); + int opcode = BMO_opcode_from_opname(opname); #ifdef DEBUG BM_ELEM_INDEX_VALIDATE(bm, "pre bmo", opname); @@ -1522,20 +1521,27 @@ static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], cons return i; } -static int bmo_opname_to_opcode(const char *opname) +int BMO_opcode_from_opname(const char *opname) { - int i; - for (i = 0; i < bmo_opdefines_total; i++) { - if (STREQ(opname, bmo_opdefines[i]->opname)) { + const unsigned int tot = bmo_opdefines_total; + unsigned int i; + for (i = 0; i < tot; i++) { + if (STREQ(bmo_opdefines[i]->opname, opname)) { return i; } } - - fprintf(stderr, "%s: could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname); return -1; } +static int BMO_opcode_from_opname_check(const char *opname) +{ + int i = BMO_opcode_from_opname(opname); + if (i == -1) + fprintf(stderr, "%s: could not find bmesh slot for name %s! (bmesh internal error)\n", __func__, opname); + return i; +} + /** * \brief Format Strings for #BMOperator Initialization. * @@ -1628,10 +1634,11 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, fmt += i + (noslot ? 0 : 1); - i = bmo_opname_to_opcode(opname); + i = BMO_opcode_from_opname_check(opname); if (i == -1) { MEM_freeN(ofmt); + BLI_assert(0); return false; } diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h index 16b38c340ff..ff0fc285dc3 100644 --- a/source/blender/bmesh/intern/bmesh_operators.h +++ b/source/blender/bmesh/intern/bmesh_operators.h @@ -95,6 +95,13 @@ enum { VPATH_SELECT_TOPOLOGICAL }; +/* Poke face center calculation */ +enum { + BMOP_POKE_MEAN_WEIGHTED = 0, + BMOP_POKE_MEAN, + BMOP_POKE_BOUNDS +}; + extern const BMOpDefine *bmo_opdefines[]; extern const int bmo_opdefines_total; diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h index 79e688bd5ff..2a67407b261 100644 --- a/source/blender/bmesh/intern/bmesh_operators_private.h +++ b/source/blender/bmesh/intern/bmesh_operators_private.h @@ -65,7 +65,8 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op); void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op); void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op); void bmo_find_doubles_exec(BMesh *bm, BMOperator *op); -void bmo_inset_exec(BMesh *bm, BMOperator *op); +void bmo_inset_individual_exec(BMesh *bm, BMOperator *op); +void bmo_inset_region_exec(BMesh *bm, BMOperator *op); void bmo_join_triangles_exec(BMesh *bm, BMOperator *op); void bmo_mesh_to_bmesh_exec(BMesh *bm, BMOperator *op); void bmo_mirror_exec(BMesh *bm, BMOperator *op); @@ -73,6 +74,7 @@ void bmo_object_load_bmesh_exec(BMesh *bm, BMOperator *op); void bmo_pointmerge_exec(BMesh *bm, BMOperator *op); void bmo_pointmerge_facedata_exec(BMesh *bm, BMOperator *op); void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op); +void bmo_poke_exec(BMesh *bm, BMOperator *op); void bmo_region_extend_exec(BMesh *bm, BMOperator *op); void bmo_remove_doubles_exec(BMesh *bm, BMOperator *op); void bmo_reverse_colors_exec(BMesh *bm, BMOperator *op); diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index d235aaaa622..525dd5b1f9c 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -337,6 +337,34 @@ void BM_face_calc_center_mean(BMFace *f, float r_cent[3]) } /** + * computes the center of a face, using the mean average + * weighted by edge length + */ +void BM_face_calc_center_mean_weighted(BMFace *f, float r_cent[3]) +{ + BMLoop *l_iter; + BMLoop *l_first; + float totw = 0.0f; + float w_prev; + + zero_v3(r_cent); + + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + w_prev = BM_edge_calc_length(l_iter->prev->e); + do { + const float w_curr = BM_edge_calc_length(l_iter->e); + const float w = (w_curr + w_prev); + madd_v3_v3fl(r_cent, l_iter->v->co, w); + totw += w; + w_prev = w_curr; + } while ((l_iter = l_iter->next) != l_first); + + if (totw != 0.0f) + mul_v3_fl(r_cent, 1.0f / (float) totw); +} + +/** * COMPUTE POLY PLANE * * Projects a set polygon's vertices to diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h index c439a41f672..d857ba77fe7 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.h +++ b/source/blender/bmesh/intern/bmesh_polygon.h @@ -37,6 +37,7 @@ float BM_face_calc_area(BMFace *f); float BM_face_calc_perimeter(BMFace *f); void BM_face_calc_center_bounds(BMFace *f, float center[3]); void BM_face_calc_center_mean(BMFace *f, float center[3]); +void BM_face_calc_center_mean_weighted(BMFace *f, float center[3]); void BM_face_normal_update(BMFace *f); void BM_face_normal_update_vcos(BMesh *bm, BMFace *f, float no[3], diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c index a3656ce5b74..d8ed511bc94 100644 --- a/source/blender/bmesh/operators/bmo_inset.c +++ b/source/blender/bmesh/operators/bmo_inset.c @@ -24,14 +24,14 @@ * \ingroup bmesh * * Inset face regions. + * Inset individual faces. * - * TODO - * - Inset indervidual faces. */ #include "MEM_guardedalloc.h" #include "BLI_math.h" +#include "BLI_array.h" #include "bmesh.h" @@ -39,6 +39,227 @@ #define ELE_NEW 1 + + +/* -------------------------------------------------------------------- */ +/* Inset Individual */ + + +/* Holds Per-Face Inset Edge Data */ +typedef struct EdgeInsetInfo { + float no[3]; + BMEdge *e_old; + BMEdge *e_new; +} EdgeInsetInfo; + +/** + * Individual Face Inset. + * Find all tagged faces (f), duplicate edges around faces, inset verts of + * created edges, create new faces between old and new edges, fill face + * between connected new edges, kill old face (f). + */ +void bmo_inset_individual_exec(BMesh *bm, BMOperator *op) +{ + BMEdge **f_edges = NULL; + BMVert **f_verts = NULL; + BMFace *f; + + BMOIter oiter; + EdgeInsetInfo *eiinfo_arr = NULL; + + BLI_array_declare(eiinfo_arr); + BLI_array_declare(f_edges); + BLI_array_declare(f_verts); + + const float thickness = BMO_slot_float_get(op->slots_in, "thickness"); + const float depth = BMO_slot_float_get(op->slots_in, "depth"); + const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset"); + + /* Only tag faces in slot */ + BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); + + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); + + BMO_ITER(f, &oiter, op->slots_in, "faces", BM_FACE) { + BMLoop *l_iter, *l_first; + BMLoop *l_iter_inner = NULL; + int i; + + BLI_array_empty(f_verts); + BLI_array_empty(f_edges); + BLI_array_empty(eiinfo_arr); + BLI_array_grow_items(f_verts, f->len); + BLI_array_grow_items(f_edges, f->len); + BLI_array_grow_items(eiinfo_arr, f->len); + + /* create verts */ + i = 0; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + f_verts[i] = BM_vert_create(bm, l_iter->v->co, l_iter->v, 0); + i++; + } while ((l_iter = l_iter->next) != l_first); + + /* make edges */ + i = 0; + l_iter = l_first; + do { + f_edges[i] = BM_edge_create(bm, f_verts[i], f_verts[(i + 1) % f->len], l_iter->e, 0); + + eiinfo_arr[i].e_new = f_edges[i]; + eiinfo_arr[i].e_old = l_iter->e; + BM_edge_calc_face_tangent(l_iter->e, l_iter, eiinfo_arr[i].no); + + /* Tagging (old elements) required when iterating over edges + * connected to verts for translation vector calculation */ + BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG); + BM_elem_index_set(l_iter->e, i); /* set_dirty! */ + i++; + } while ((l_iter = l_iter->next) != l_first); + /* done with edges */ + + bm->elem_index_dirty |= BM_EDGE; + + /* Calculate translation vector for new */ + l_iter = l_first; + do { + EdgeInsetInfo *ei_prev = &eiinfo_arr[BM_elem_index_get(l_iter->prev->e)]; + EdgeInsetInfo *ei_next = &eiinfo_arr[BM_elem_index_get(l_iter->e)]; + float tvec[3]; + float v_new_co[3]; + int index = 0; + + add_v3_v3v3(tvec, ei_prev->no, ei_next->no); + normalize_v3(tvec); + + /* l->e is traversed in order */ + index = BM_elem_index_get(l_iter->e); + + copy_v3_v3(v_new_co, eiinfo_arr[index].e_new->v1->co); + + if (use_even_offset) { + mul_v3_fl(tvec, shell_angle_to_dist(angle_normalized_v3v3(ei_prev->no, ei_next->no) / 2.0f)); + } + + /* Modify vertices and their normals */ + madd_v3_v3fl(v_new_co, tvec, thickness); + + /* Set normal, add depth and write new vertex position*/ + copy_v3_v3(eiinfo_arr[index].e_new->v1->no, f->no); + + madd_v3_v3fl(v_new_co, f->no, depth); + + copy_v3_v3(eiinfo_arr[index].e_new->v1->co, v_new_co); + } while ((l_iter = l_iter->next) != l_first); + + { + BMFace *f_new_inner; + /* Create New Inset Faces */ + f_new_inner = BM_face_create(bm, f_verts, f_edges, f->len, 0); + if (UNLIKELY(f_new_inner == NULL)) { + BMO_error_raise(bm, op, BMERR_MESH_ERROR, "Inset failed: could not create inner face."); + BLI_array_free(f_edges); + BLI_array_free(f_verts); + BLI_array_free(eiinfo_arr); + return; + } + + /* Copy Face Data */ + BM_elem_attrs_copy(bm, bm, f, f_new_inner); + // Don't tag, gives more useful inner/outer select option + // BMO_elem_flag_enable(bm, f_new_inner, ELE_NEW); + + l_iter_inner = BM_FACE_FIRST_LOOP(f_new_inner); + } + + l_iter = l_first; + do { + BMFace *f_new_outer; + + BMLoop *l_iter_sub; + BMLoop *l_a = NULL; + BMLoop *l_b = NULL; + BMLoop *l_a_other = NULL; + BMLoop *l_b_other = NULL; + BMLoop *l_shared = NULL; + + BM_elem_attrs_copy(bm, bm, l_iter, l_iter_inner); + + f_new_outer = BM_face_create_quad_tri(bm, + l_iter->v, + l_iter->next->v, + l_iter_inner->next->v, + l_iter_inner->v, + f, false); + + if (UNLIKELY(f_new_outer == NULL)) { + BMO_error_raise(bm, op, BMERR_MESH_ERROR, "Inset failed: could not create an outer face."); + BLI_array_free(f_edges); + BLI_array_free(f_verts); + BLI_array_free(eiinfo_arr); + return; + } + + BM_elem_attrs_copy(bm, bm, f, f_new_outer); + BMO_elem_flag_enable(bm, f_new_outer, ELE_NEW); + BM_elem_flag_enable(f_new_outer, BM_ELEM_TAG); + + /* Copy Loop Data */ + l_a = BM_FACE_FIRST_LOOP(f_new_outer); + l_b = l_a->next; + + l_iter_sub = l_iter; + + /* Skip old face f and new inset face. + * If loop if found we are a boundary. This + * is required as opposed to BM_edge_is_boundary() + * Because f_new_outer shares an edge with f */ + do { + if (l_iter_sub->f != f && l_iter_sub->f != f_new_outer) { + l_shared = l_iter_sub; + break; + } + } while ((l_iter_sub = l_iter_sub->radial_next) != l_iter); + + if (l_shared) { + BM_elem_attrs_copy(bm, bm, l_shared, l_a->next); + BM_elem_attrs_copy(bm, bm, l_shared->next, l_a); + } + else { + l_a_other = BM_edge_other_loop(l_a->e, l_a); + l_b_other = l_a_other->next; + BM_elem_attrs_copy(bm, bm, l_a_other, l_a); + BM_elem_attrs_copy(bm, bm, l_b_other, l_b); + } + + /* Move to the last two loops in new face */ + l_a = l_b->next; + l_b = l_a->next; + + /* This loop should always have >1 radials + * (associated edge connects new and old face) */ + BM_elem_attrs_copy(bm, bm, l_iter, l_b); + BM_elem_attrs_copy(bm, bm, l_iter->next, l_a); + + } while ((l_iter_inner = l_iter_inner->next), + (l_iter = l_iter->next) != l_first); + + BM_face_kill(bm, f); + } + + /* we could flag new edges/verts too, is it useful? */ + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW); + + BLI_array_free(f_verts); + BLI_array_free(f_edges); + BLI_array_free(eiinfo_arr); +} + + + +/* -------------------------------------------------------------------- */ +/* Inset Region */ + typedef struct SplitEdgeInfo { float no[3]; float length; @@ -95,7 +316,7 @@ static BMLoop *bm_edge_is_mixed_face_tag(BMLoop *l) * - inset the new edges into their faces. */ -void bmo_inset_exec(BMesh *bm, BMOperator *op) +void bmo_inset_region_exec(BMesh *bm, BMOperator *op) { const bool use_outset = BMO_slot_bool_get(op->slots_in, "use_outset"); const bool use_boundary = BMO_slot_bool_get(op->slots_in, "use_boundary") && (use_outset == false); diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c index 5e4fa29d953..edbb19afc62 100644 --- a/source/blender/bmesh/operators/bmo_join_triangles.c +++ b/source/blender/bmesh/operators/bmo_join_triangles.c @@ -33,11 +33,11 @@ #include "DNA_meshdata_types.h" -#include "BKE_customdata.h" - #include "BLI_math.h" #include "BLI_array.h" +#include "BKE_customdata.h" + #include "bmesh.h" #include "intern/bmesh_operators_private.h" /* own include */ diff --git a/source/blender/bmesh/operators/bmo_poke.c b/source/blender/bmesh/operators/bmo_poke.c new file mode 100644 index 00000000000..7105210da04 --- /dev/null +++ b/source/blender/bmesh/operators/bmo_poke.c @@ -0,0 +1,141 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Francisco De La Cruz + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/operators/bmo_poke.c + * \ingroup bmesh + * + * Pokes a face. + * + * Splits a face into a triangle fan. + */ + +#include "BLI_math.h" + +#include "bmesh.h" + +#include "intern/bmesh_operators_private.h" /* own include */ + +#define ELE_NEW 1 + +/** + * Pokes a face + * + * Splits a face into a triangle fan. + * Iterate over all selected faces, create a new center vertex and + * create triangles between original face edges and new center vertex. + */ +void bmo_poke_exec(BMesh *bm, BMOperator *op) +{ + BMOIter oiter; + BMFace *f; + + const float offset = BMO_slot_float_get(op->slots_in, "offset"); + const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); + const int center_mode = BMO_slot_int_get(op->slots_in, "center_mode"); + void (*bm_face_calc_center_fn)(BMFace *f, float r_cent[3]); + + switch (center_mode) { + case BMOP_POKE_MEAN_WEIGHTED: + bm_face_calc_center_fn = BM_face_calc_center_mean_weighted; + break; + case BMOP_POKE_BOUNDS: + bm_face_calc_center_fn = BM_face_calc_center_bounds; + break; + case BMOP_POKE_MEAN: + bm_face_calc_center_fn = BM_face_calc_center_mean; + break; + default: + BLI_assert(0); + break; + } + + BMO_ITER(f, &oiter, op->slots_in, "faces", BM_FACE) { + BMFace *f_new; + float f_center[3]; + BMVert *v_center = NULL; + BMLoop *l_iter, *l_first; + /* only interpolate the centeral loop from the face once, + * then copy to all others in the fan */ + BMLoop *l_center_example; + + /* 1.0 or the average length from the center to the face verts */ + float offset_fac; + + int i; + + bm_face_calc_center_fn(f, f_center); + v_center = BM_vert_create(bm, f_center, NULL, 0); + BMO_elem_flag_enable(bm, v_center, ELE_NEW); + + /* handled by BM_loop_interp_from_face */ + // BM_vert_interp_from_face(bm, v_center, f); + + if (use_relative_offset) { + offset_fac = 0.0f; + } + else { + offset_fac = 1.0f; + } + + i = 0; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BMLoop *l_new; + + f_new = BM_face_create_quad_tri(bm, l_iter->v, l_iter->next->v, v_center, NULL, f, false); + l_new = BM_FACE_FIRST_LOOP(f_new); + + if (i == 0) { + l_center_example = l_new->prev; + BM_loop_interp_from_face(bm, l_center_example, f, true, true); + } + else { + BM_elem_attrs_copy(bm, bm, l_center_example, l_new->prev); + } + + /* Copy Loop Data */ + BM_elem_attrs_copy(bm, bm, l_iter, l_new); + BM_elem_attrs_copy(bm, bm, l_iter->next, l_new->next); + + BMO_elem_flag_enable(bm, f_new, ELE_NEW); + + if (use_relative_offset) { + offset_fac += len_v3v3(f_center, l_iter->v->co); + } + + } while (i++, (l_iter = l_iter->next) != l_first); + + if (use_relative_offset) { + offset_fac /= (float)f->len; + } + /* else remain at 1.0 */ + + copy_v3_v3(v_center->no, f->no); + madd_v3_v3fl(v_center->co, v_center->no, offset * offset_fac); + + /* Kill Face */ + BM_face_kill(bm, f); + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, ELE_NEW); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW); +} |