Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/bmesh')
-rw-r--r--source/blender/bmesh/bmesh.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c1
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c44
-rw-r--r--source/blender/bmesh/intern/bmesh_query.h10
-rw-r--r--source/blender/bmesh/operators/bmo_extrude.c65
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c57
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c12
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.h1
9 files changed, 175 insertions, 31 deletions
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index 7d2100c0f65..9b5072e8e16 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -188,10 +188,6 @@
* - Use two different iterator types for BMO map/buffer types.
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "DNA_customdata_types.h" /* BMesh struct in bmesh_class.h uses */
#include "DNA_listBase.h" /* selection history uses */
@@ -199,6 +195,10 @@ extern "C" {
#include <stdio.h>
#include <stdlib.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "bmesh_class.h"
/* include the rest of the API */
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index dad459b93ca..04cdc0020d9 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1052,6 +1052,7 @@ static BMOpDefine bmo_extrude_face_region_def = {
{"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry (requires ``geom`` to include edges). */
{"use_normal_flip", BMO_OP_SLOT_BOOL}, /* Create faces with reversed direction. */
{"use_normal_from_adjacent", BMO_OP_SLOT_BOOL}, /* Use winding from surrounding faces instead of this region. */
+ {"use_dissolve_ortho_edges", BMO_OP_SLOT_BOOL}, /* Dissolve edges whose faces form a flat surface. */
{"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */
{{'\0'}},
},
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index dbd2bf076c6..5af812d1b1d 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -21,14 +21,14 @@
* \ingroup bmesh
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "BLI_ghash.h"
#include <stdarg.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/**
* operators represent logical, executable mesh modules. all topological
* operations involving a bmesh has to go through them.
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index 64950411fed..e000b253000 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -1568,6 +1568,41 @@ float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq,
}
/**
+ * A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates.
+ */
+float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
+ const float normal_fallback[3],
+ float const (*vertexCos)[3],
+ const float epsilon_sq,
+ float r_normal[3])
+{
+ const int i_prev = BM_elem_index_get(l->prev->v);
+ const int i_next = BM_elem_index_get(l->next->v);
+ const int i = BM_elem_index_get(l->v);
+
+ float v1[3], v2[3], v_tmp[3];
+ sub_v3_v3v3(v1, vertexCos[i_prev], vertexCos[i]);
+ sub_v3_v3v3(v2, vertexCos[i_next], vertexCos[i]);
+
+ const float fac = ((v2[0] == 0.0f) ?
+ ((v2[1] == 0.0f) ? ((v2[2] == 0.0f) ? 0.0f : v1[2] / v2[2]) :
+ v1[1] / v2[1]) :
+ v1[0] / v2[0]);
+
+ mul_v3_v3fl(v_tmp, v2, fac);
+ sub_v3_v3(v_tmp, v1);
+ if (fac != 0.0f && !is_zero_v3(v1) && len_squared_v3(v_tmp) > epsilon_sq) {
+ /* Not co-linear, we can compute cross-product and normalize it into normal. */
+ cross_v3_v3v3(r_normal, v1, v2);
+ return normalize_v3(r_normal);
+ }
+ else {
+ copy_v3_v3(r_normal, normal_fallback);
+ return 0.0f;
+ }
+}
+
+/**
* #BM_loop_calc_face_normal_safe_ex with pre-defined sane epsilon.
*
* Since this doesn't scale based on triangle size, fixed value works well.
@@ -1577,6 +1612,15 @@ float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3])
return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal);
}
+float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
+ const float normal_fallback[3],
+ float const (*vertexCos)[3],
+ float r_normal[3])
+
+{
+ return BM_loop_calc_face_normal_safe_vcos_ex(l, normal_fallback, vertexCos, 1e-5f, r_normal);
+}
+
/**
* \brief BM_loop_calc_face_normal
*
diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h
index aaf8191c5db..7e07059d4d8 100644
--- a/source/blender/bmesh/intern/bmesh_query.h
+++ b/source/blender/bmesh/intern/bmesh_query.h
@@ -142,6 +142,16 @@ float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL(
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon, float r_normal[3])
ATTR_NONNULL();
+float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
+ const float normal_fallback[3],
+ float const (*vertexCos)[3],
+ const float epsilon_sq,
+ float r_normal[3]) ATTR_NONNULL();
+float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
+ const float normal_fallback[3],
+ float const (*vertexCos)[3],
+ float r_normal[3]) ATTR_NONNULL();
+
void BM_loop_calc_face_direction(const BMLoop *l, float r_normal[3]);
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]);
diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c
index 7a7f4a14db3..3c63f4a60d6 100644
--- a/source/blender/bmesh/operators/bmo_extrude.c
+++ b/source/blender/bmesh/operators/bmo_extrude.c
@@ -39,6 +39,7 @@ enum {
EXT_INPUT = 1,
EXT_KEEP = 2,
EXT_DEL = 4,
+ EXT_TAG = 8,
};
#define VERT_MARK 1
@@ -335,6 +336,8 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip");
const bool use_normal_from_adjacent = BMO_slot_bool_get(op->slots_in,
"use_normal_from_adjacent");
+ const bool use_dissolve_ortho_edges = BMO_slot_bool_get(op->slots_in,
+ "use_dissolve_ortho_edges");
/* initialize our sub-operators */
BMO_op_initf(bm,
@@ -442,6 +445,24 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
}
}
+ BMVert **dissolve_verts = NULL;
+ int dissolve_verts_len = 0;
+ float average_normal[3];
+ if (use_dissolve_ortho_edges) {
+ /* Calc average normal. */
+ zero_v3(average_normal);
+ BMO_ITER (f, &siter, dupeop.slots_out, "geom.out", BM_FACE) {
+ add_v3_v3(average_normal, f->no);
+ }
+ if (normalize_v3(average_normal) == 0.0f) {
+ average_normal[2] = 1.0f;
+ }
+
+ /* Allocate array to store possible vertices that will be dissolved. */
+ int boundary_verts_len = BMO_slot_map_count(dupeop.slots_out, "boundary_map.out");
+ dissolve_verts = MEM_mallocN((size_t)boundary_verts_len * sizeof(*dissolve_verts), __func__);
+ }
+
BMO_slot_copy(&dupeop, slots_out, "geom.out", op, slots_out, "geom.out");
slot_edges_exclude = BMO_slot_get(op->slots_in, "edges_exclude");
@@ -483,6 +504,16 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
continue;
}
+ BMFace *join_face = NULL;
+ if (use_dissolve_ortho_edges) {
+ if (BM_edge_is_boundary(e)) {
+ join_face = e->l->f;
+ if (fabs(dot_v3v3(average_normal, join_face->no)) > 0.0001f) {
+ join_face = NULL;
+ }
+ }
+ }
+
bool edge_normal_flip;
if (use_normal_from_adjacent == false) {
/* Orient loop to give same normal as a loop of 'e_new'
@@ -541,7 +572,22 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
#endif
- bm_extrude_copy_face_loop_attributes(bm, f);
+ if (join_face) {
+ BMVert *v1 = e->v1;
+ BMVert *v2 = e->v2;
+ if (!BMO_elem_flag_test(bm, v1, EXT_TAG)) {
+ BMO_elem_flag_enable(bm, v1, EXT_TAG);
+ dissolve_verts[dissolve_verts_len++] = v1;
+ }
+ if (!BMO_elem_flag_test(bm, v2, EXT_TAG)) {
+ BMO_elem_flag_enable(bm, v2, EXT_TAG);
+ dissolve_verts[dissolve_verts_len++] = v2;
+ }
+ bmesh_kernel_join_face_kill_edge(bm, join_face, f, e);
+ }
+ else {
+ bm_extrude_copy_face_loop_attributes(bm, f);
+ }
}
/* link isolated vert */
@@ -559,6 +605,23 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
BM_edge_create(bm, v, v2, NULL, BM_CREATE_NO_DOUBLE);
}
+ if (dissolve_verts) {
+ BMVert **v_iter = &dissolve_verts[0];
+ for (int i = dissolve_verts_len; i--; v_iter++) {
+ v = *v_iter;
+ e = v->e;
+ BMEdge *e_other = BM_DISK_EDGE_NEXT(e, v);
+ if ((e_other == e) || (BM_DISK_EDGE_NEXT(e_other, v) == e)) {
+ /* Lose edge or BMVert is edge pair. */
+ BM_edge_collapse(bm, e, v, true, false);
+ }
+ else {
+ BLI_assert(!BM_vert_is_edge_pair(v));
+ }
+ }
+ MEM_freeN(dissolve_verts);
+ }
+
/* cleanup */
if (delorig) {
BMO_op_finish(bm, &delop);
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index 64687ac154c..d661859c8e3 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -1393,16 +1393,15 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
BMVert *v1, *v2, *lastv1 = NULL, *lastv2 = NULL, *cent1, *cent2, *firstv1, *firstv2;
BMFace *f;
float vec[3], mat[4][4], phi, phid;
- float dia1 = BMO_slot_float_get(op->slots_in, "diameter1");
- float dia2 = BMO_slot_float_get(op->slots_in, "diameter2");
- float depth = BMO_slot_float_get(op->slots_in, "depth");
+ const float dia1 = BMO_slot_float_get(op->slots_in, "diameter1");
+ const float dia2 = BMO_slot_float_get(op->slots_in, "diameter2");
+ const float depth_half = 0.5f * BMO_slot_float_get(op->slots_in, "depth");
int segs = BMO_slot_int_get(op->slots_in, "segments");
const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends");
const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris");
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
- int a;
if (!segs) {
return;
@@ -1413,16 +1412,15 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
phid = 2.0f * (float)M_PI / segs;
phi = 0;
- depth *= 0.5f;
if (cap_ends) {
vec[0] = vec[1] = 0.0f;
- vec[2] = -depth;
+ vec[2] = -depth_half;
mul_m4_v3(mat, vec);
cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
vec[0] = vec[1] = 0.0f;
- vec[2] = depth;
+ vec[2] = depth_half;
mul_m4_v3(mat, vec);
cent2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
@@ -1431,23 +1429,26 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
BMO_vert_flag_enable(bm, cent2, VERT_MARK);
}
- for (a = 0; a < segs; a++, phi += phid) {
+ const int side_faces_len = segs - 1;
+ BMFace **side_faces = MEM_mallocN(sizeof(*side_faces) * side_faces_len, __func__);
+
+ for (int i = 0; i < segs; i++, phi += phid) {
vec[0] = dia1 * sinf(phi);
vec[1] = dia1 * cosf(phi);
- vec[2] = -depth;
+ vec[2] = -depth_half;
mul_m4_v3(mat, vec);
v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
vec[0] = dia2 * sinf(phi);
vec[1] = dia2 * cosf(phi);
- vec[2] = depth;
+ vec[2] = depth_half;
mul_m4_v3(mat, vec);
v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
BMO_vert_flag_enable(bm, v1, VERT_MARK);
BMO_vert_flag_enable(bm, v2, VERT_MARK);
- if (a) {
+ if (i) {
if (cap_ends) {
f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP);
if (calc_uvs) {
@@ -1466,6 +1467,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
if (calc_uvs) {
BMO_face_flag_enable(bm, f, FACE_MARK);
}
+ side_faces[i - 1] = f;
}
else {
firstv1 = v1;
@@ -1476,10 +1478,6 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
lastv2 = v2;
}
- if (!a) {
- return;
- }
-
if (cap_ends) {
f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP);
if (calc_uvs) {
@@ -1503,11 +1501,38 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs, cap_ends, FACE_MARK, cd_loop_uv_offset);
}
+ /* Collapse vertices at the first end. */
+ if (dia1 == 0.0f) {
+ if (cap_ends) {
+ BM_vert_kill(bm, cent1);
+ }
+ for (int i = 0; i < side_faces_len; i++) {
+ f = side_faces[i];
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ BM_edge_collapse(bm, l->prev->e, l->prev->v, true, true);
+ }
+ }
+
+ /* Collapse vertices at the second end. */
+ if (dia2 == 0.0f) {
+ if (cap_ends) {
+ BM_vert_kill(bm, cent2);
+ }
+ for (int i = 0; i < side_faces_len; i++) {
+ f = side_faces[i];
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ BM_edge_collapse(bm, l->next->e, l->next->v, true, true);
+ }
+ }
+
if (!cap_tris) {
BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW);
}
- BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.0000005 * depth);
+ if (side_faces != NULL) {
+ MEM_freeN(side_faces);
+ }
+
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 0891070ce77..720eb34bda7 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -997,10 +997,10 @@ static bool point_between_edges(float co[3], BMVert *v, BMFace *f, EdgeHalf *e1,
* record the change in offset_l (or offset_r); later we can tell that a change has happened
* because the offset will differ from its original value in offset_l_spec (or offset_r_spec).
*
- * \param edges_between If this is true, there are edges between e1 and e2 in CCW order so they
+ * \param edges_between: If this is true, there are edges between e1 and e2 in CCW order so they
* don't share a common face. We want the meeting point to be on an existing face so it
* should be dropped onto one of the intermediate faces, if possible.
- * \param e_in_plane If we need to drop from the calculated offset lines to one of the faces,
+ * \param e_in_plane: If we need to drop from the calculated offset lines to one of the faces,
* we don't want to drop onto the 'in plane' face, so if this is not null skip this edge's faces.
*/
static void offset_meet(EdgeHalf *e1,
@@ -2601,13 +2601,13 @@ static void adjust_miter_inner_coords(BevelParams *bp, BevVert *bv, EdgeHalf *em
* to be a subsequent pass to make the widths as consistent as possible.
* Doesn't make the actual BMVerts.
*
- * For a width consistency pass, we just recalculate the coordinates of the BoundVerts. If the
+ * For a width consistency pass, we just recalculate the coordinates of the #BoundVerts. If the
* other ends have been (re)built already, then we copy the offsets from there to match, else we
* use the ideal (user-specified) widths.
*
- * \param construct The first time through, construct will be true and we are making the BoundVerts
- * and setting up the BoundVert and EdgeHalf pointers appropriately. Also, if construct, decide on
- * the mesh pattern that will be used inside the boundary.
+ * \param construct: The first time through, construct will be true and we are making the
+ * #BoundVerts and setting up the #BoundVert and #EdgeHalf pointers appropriately.
+ * Also, if construct, decide on the mesh pattern that will be used inside the boundary.
*/
static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
{
diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h
index 479a8a3f6d6..8562e584ec9 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.h
+++ b/source/blender/bmesh/tools/bmesh_bevel.h
@@ -47,4 +47,5 @@ void BM_mesh_bevel(BMesh *bm,
const bool use_custom_profile,
const struct CurveProfile *custom_profile,
const int vmesh_method);
+
#endif /* __BMESH_BEVEL_H__ */