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.h2
-rw-r--r--source/blender/bmesh/bmesh_class.h29
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c3
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c531
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h55
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c51
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c5
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h9
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c2
-rw-r--r--source/blender/bmesh/operators/bmo_bevel.c7
-rw-r--r--source/blender/bmesh/operators/bmo_similar.c64
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c385
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.h3
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c21
16 files changed, 960 insertions, 212 deletions
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index 8b0b8a282f5..138b8b7c51f 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -84,7 +84,7 @@
* Edges and Vertices in BMesh are primitive structures.
*
* \note There can be more than one edge between two vertices in BMesh,
- * though the rest of Blender (e.g. DerivedMesh, CDDM, CCGSubSurf, etc) does not support this.
+ * though the rest of Blender (i.e. DNA and evaluated Mesh) does not support this.
* So it should only occur temporarily during editing operations.
*
*
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 10e2892c5a5..70884454ce5 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -38,6 +38,8 @@ struct BMEdge;
struct BMLoop;
struct BMFace;
+struct MLoopNorSpaceArray;
+
struct BLI_mempool;
/* note: it is very important for BMHeader to start with two
@@ -236,6 +238,9 @@ typedef struct BMesh {
struct BLI_mempool *looplistpool;
#endif
+ struct MLoopNorSpaceArray *lnor_spacearr;
+ char spacearr_dirty;
+
/* should be copy of scene select mode */
/* stored in BMEditMesh too, this is a bit confusing,
* make sure they're in sync!
@@ -263,9 +268,33 @@ enum {
BM_FACE = 8
};
+typedef struct BMLoopNorEditData {
+ int loop_index;
+ BMLoop *loop;
+ float niloc[3];
+ float nloc[3];
+ float *loc;
+ short *clnors_data;
+} BMLoopNorEditData;
+
+typedef struct BMLoopNorEditDataArray {
+ BMLoopNorEditData *lnor_editdata;
+ /* This one has full amount of loops, used to map loop index to actual BMLoopNorEditData struct. */
+ BMLoopNorEditData **lidx_to_lnor_editdata;
+
+ int cd_custom_normal_offset;
+ int totloop;
+} BMLoopNorEditDataArray;
+
#define BM_ALL (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE)
#define BM_ALL_NOLOOP (BM_VERT | BM_EDGE | BM_FACE)
+enum {
+ BM_SPACEARR_DIRTY = 1 << 0,
+ BM_SPACEARR_DIRTY_ALL = 1 << 1,
+ BM_SPACEARR_BMO_SET = 1 << 2,
+};
+
/* args for _Generic */
#define _BM_GENERIC_TYPE_ELEM_NONCONST \
void *, BMVert *, BMEdge *, BMLoop *, BMFace *, \
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index 97f1bad08b7..bb5199fa0c8 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -36,7 +36,8 @@
#include "BLT_translation.h"
-#include "BKE_DerivedMesh.h"
+#include "DNA_meshdata_types.h"
+
#include "BKE_mesh.h"
#include "bmesh.h"
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 10a03050d4b..1e53180396e 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -863,7 +863,7 @@ void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
/* Calculate a plane that is rightangles to the edge/vert/faces normal
* also make the plane run along an axis that is related to the geometry,
- * because this is used for the manipulators Y axis. */
+ * because this is used for the gizmos Y axis. */
void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
{
if (ese->htype == BM_VERT) {
@@ -895,7 +895,7 @@ void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
else {
/* the plane is simple, it runs along the edge
* however selecting different edges can swap the direction of the y axis.
- * this makes it less likely for the y axis of the manipulator
+ * this makes it less likely for the y axis of the gizmo
* (running along the edge).. to flip less often.
* at least its more predictable */
if (eed->v2->co[1] > eed->v1->co[1]) { /* check which to do first */
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 185e5412b3d..a454fb7e948 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -30,6 +30,7 @@
#include "DNA_listBase.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BLI_linklist_stack.h"
#include "BLI_listbase.h"
@@ -260,6 +261,11 @@ void BM_mesh_data_free(BMesh *bm)
BLI_freelistN(&bm->selected);
+ if (bm->lnor_spacearr) {
+ BKE_lnor_spacearr_free(bm->lnor_spacearr);
+ MEM_freeN(bm->lnor_spacearr);
+ }
+
BMO_error_clear(bm);
}
@@ -313,6 +319,9 @@ void BM_mesh_free(BMesh *bm)
* Helpers for #BM_mesh_normals_update and #BM_verts_calc_normal_vcos
*/
+/* We use that existing internal API flag, assuming no other tool using it would run concurrently to clnors editing. */
+#define BM_LNORSPACE_UPDATE _FLAG_MF
+
typedef struct BMEdgesCalcVectorsData {
/* Read-only data. */
const float (*vcos)[3];
@@ -638,7 +647,8 @@ bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
* Will use first clnors_data array, and fallback to cd_loop_clnors_offset (use NULL and -1 to not use clnors). */
static void bm_mesh_loops_calc_normals(
BMesh *bm, const float (*vcos)[3], const float (*fnos)[3], float (*r_lnos)[3],
- MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset)
+ MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2],
+ const int cd_loop_clnors_offset, const bool do_rebuild)
{
BMIter fiter;
BMFace *f_curr;
@@ -694,6 +704,11 @@ static void bm_mesh_loops_calc_normals(
l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
do {
+ if (do_rebuild && !BM_ELEM_API_FLAG_TEST(l_curr, BM_LNORSPACE_UPDATE) &&
+ !(bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL))
+ {
+ continue;
+ }
/* A smooth edge, we have to check for cyclic smooth fan case.
* If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge as
* 'entry point', otherwise we can skip it. */
@@ -894,7 +909,10 @@ static void bm_mesh_loops_calc_normals(
clnors_avg[0] /= clnors_nbr;
clnors_avg[1] /= clnors_nbr;
/* Fix/update all clnors of this fan with computed average value. */
- printf("Invalid clnors in this fan!\n");
+
+ /* Prints continuously when merge custom normals, so commenting. */
+ /* printf("Invalid clnors in this fan!\n"); */
+
while ((clnor = BLI_SMALLSTACK_POP(clnors))) {
//print_v2("org clnor", clnor);
clnor[0] = (short)clnors_avg[0];
@@ -1009,7 +1027,8 @@ void BM_mesh_loop_normals_update(
void BM_loops_calc_normal_vcos(
BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*fnos)[3],
const bool use_split_normals, const float split_angle, float (*r_lnos)[3],
- MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset)
+ MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2],
+ const int cd_loop_clnors_offset, const bool do_rebuild)
{
const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
@@ -1019,7 +1038,8 @@ void BM_loops_calc_normal_vcos(
bm_mesh_edges_sharp_tag(bm, vnos, fnos, r_lnos, has_clnors ? (float)M_PI : split_angle, false);
/* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
- bm_mesh_loops_calc_normals(bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset);
+ bm_mesh_loops_calc_normals(
+ bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset, do_rebuild);
}
else {
BLI_assert(!r_lnors_spacearr);
@@ -1041,56 +1061,420 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
bm_mesh_edges_sharp_tag(bm, NULL, NULL, NULL, split_angle, true);
}
-static void UNUSED_FUNCTION(bm_mdisps_space_set)(Object *ob, BMesh *bm, int from, int to)
+void BM_lnorspacearr_store(BMesh *bm, float(*r_lnors)[3])
{
- /* switch multires data out of tangent space */
- if (CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
- BMEditMesh *em = BKE_editmesh_create(bm, false);
- DerivedMesh *dm = CDDM_from_editbmesh(em, true, false);
- MDisps *mdisps;
- BMFace *f;
- BMIter iter;
- // int i = 0; // UNUSED
+ BLI_assert(bm->lnor_spacearr != NULL);
- multires_set_space(dm, ob, from, to);
+ if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ BM_data_layer_add(bm, &bm->ldata, CD_CUSTOMLOOPNORMAL);
+ }
- mdisps = CustomData_get_layer(&dm->loopData, CD_MDISPS);
+ int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- BMLoop *l;
- BMIter liter;
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- MDisps *lmd = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MDISPS);
+ BM_loops_calc_normal_vcos(
+ bm, NULL, NULL, NULL, true, M_PI, r_lnors, bm->lnor_spacearr, NULL, cd_loop_clnors_offset, false);
+ bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL);
+}
- if (!lmd->disps) {
- printf("%s: warning - 'lmd->disps' == NULL\n", __func__);
+#define CLEAR_SPACEARRAY_THRESHOLD(x) ((x) / 2)
+
+void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all)
+{
+ if (bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) {
+ return;
+ }
+ if (do_invalidate_all || bm->totvertsel > CLEAR_SPACEARRAY_THRESHOLD(bm->totvert)) {
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ return;
+ }
+ if (bm->lnor_spacearr == NULL) {
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ return;
+ }
+
+ BMVert *v;
+ BMLoop *l;
+ BMIter viter, liter;
+ /* Note: we could use temp tag of BMItem for that, but probably better not use it in such a low-level func?
+ * --mont29 */
+ BLI_bitmap *done_verts = BLI_BITMAP_NEW(bm->totvert, __func__);
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ /* When we affect a given vertex, we may affect following smooth fans:
+ * - all smooth fans of said vertex;
+ * - all smooth fans of all immediate loop-neighbors vertices;
+ * This can be simplified as 'all loops of selected vertices and their immediate neighbors'
+ * need to be tagged for update.
+ */
+ BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
+ BM_ELEM_API_FLAG_ENABLE(l, BM_LNORSPACE_UPDATE);
+
+ /* Note that we only handle unselected neighbor vertices here, main loop will take care of
+ * selected ones. */
+ if ((!BM_elem_flag_test(l->prev->v, BM_ELEM_SELECT)) &&
+ !BLI_BITMAP_TEST(done_verts, BM_elem_index_get(l->prev->v)))
+ {
+
+ BMLoop *l_prev;
+ BMIter liter_prev;
+ BM_ITER_ELEM(l_prev, &liter_prev, l->prev->v, BM_LOOPS_OF_VERT) {
+ BM_ELEM_API_FLAG_ENABLE(l_prev, BM_LNORSPACE_UPDATE);
+ }
+ BLI_BITMAP_ENABLE(done_verts, BM_elem_index_get(l_prev->v));
+ }
+
+ if ((!BM_elem_flag_test(l->next->v, BM_ELEM_SELECT)) &&
+ !BLI_BITMAP_TEST(done_verts, BM_elem_index_get(l->next->v)))
+ {
+
+ BMLoop *l_next;
+ BMIter liter_next;
+ BM_ITER_ELEM(l_next, &liter_next, l->next->v, BM_LOOPS_OF_VERT) {
+ BM_ELEM_API_FLAG_ENABLE(l_next, BM_LNORSPACE_UPDATE);
+ }
+ BLI_BITMAP_ENABLE(done_verts, BM_elem_index_get(l_next->v));
}
+ }
+
+ BLI_BITMAP_ENABLE(done_verts, BM_elem_index_get(v));
+ }
+ }
+
+ MEM_freeN(done_verts);
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY;
+}
+
+void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor)
+{
+ BLI_assert(bm->lnor_spacearr != NULL);
+
+ if (!(bm->spacearr_dirty & (BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL))) {
+ return;
+ }
+ BMFace *f;
+ BMLoop *l;
+ BMIter fiter, liter;
+
+ float(*r_lnors)[3] = MEM_callocN(sizeof(*r_lnors) * bm->totloop, __func__);
+ float(*oldnors)[3] = preserve_clnor ? MEM_mallocN(sizeof(*oldnors) * bm->totloop, __func__) : NULL;
+
+ int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+
+ BM_mesh_elem_index_ensure(bm, BM_LOOP);
+
+ if (preserve_clnor) {
+ BLI_assert(bm->lnor_spacearr->lspacearr != NULL);
+
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) {
+ if (BM_ELEM_API_FLAG_TEST(l, BM_LNORSPACE_UPDATE) || bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) {
+ short(*clnor)[2] = BM_ELEM_CD_GET_VOID_P(l, cd_loop_clnors_offset);
+ int l_index = BM_elem_index_get(l);
+
+ BKE_lnor_space_custom_data_to_normal(
+ bm->lnor_spacearr->lspacearr[l_index], *clnor,
+ oldnors[l_index]);
+ }
+ }
+ }
+ }
+
+ if (bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) {
+ BKE_lnor_spacearr_clear(bm->lnor_spacearr);
+ }
+ BM_loops_calc_normal_vcos(
+ bm, NULL, NULL, NULL, true, M_PI, r_lnors, bm->lnor_spacearr, NULL, cd_loop_clnors_offset, true);
+ MEM_freeN(r_lnors);
+
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) {
+ if (BM_ELEM_API_FLAG_TEST(l, BM_LNORSPACE_UPDATE) || bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) {
+ if (preserve_clnor) {
+ short(*clnor)[2] = BM_ELEM_CD_GET_VOID_P(l, cd_loop_clnors_offset);
+ int l_index = BM_elem_index_get(l);
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], oldnors[l_index],
+ *clnor);
+ }
+ BM_ELEM_API_FLAG_DISABLE(l, BM_LNORSPACE_UPDATE);
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(oldnors);
+ bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL);
+
+#ifndef NDEBUG
+ BM_lnorspace_err(bm);
+#endif
+}
+
+void BM_lnorspace_update(BMesh *bm)
+{
+ if (bm->lnor_spacearr == NULL) {
+ bm->lnor_spacearr = MEM_callocN(sizeof(*bm->lnor_spacearr), __func__);
+ }
+ if (bm->lnor_spacearr->lspacearr == NULL) {
+ float(*lnors)[3] = MEM_callocN(sizeof(*lnors) * bm->totloop, __func__);
+
+ BM_lnorspacearr_store(bm, lnors);
+
+ MEM_freeN(lnors);
+ }
+ else if (bm->spacearr_dirty & (BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL)) {
+ BM_lnorspace_rebuild(bm, false);
+ }
+}
+
+void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges)
+{
+ BMFace *f;
+ BMEdge *e;
+ BMIter fiter, eiter;
+ BMLoop *l_curr, *l_first;
+
+ if (do_edges) {
+ int index_edge;
+ BM_ITER_MESH_INDEX(e, &eiter, bm, BM_EDGES_OF_MESH, index_edge) {
+ BMLoop *l_a, *l_b;
+
+ BM_elem_index_set(e, index_edge); /* set_inline */
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ if (BM_edge_loop_pair(e, &l_a, &l_b)) {
+ if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) && l_a->v != l_b->v) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ }
+ }
+ bm->elem_index_dirty &= ~BM_EDGE;
+ }
- if (lmd->disps && lmd->totdisp == mdisps->totdisp) {
- memcpy(lmd->disps, mdisps->disps, sizeof(float) * 3 * lmd->totdisp);
+ int index_face, index_loop = 0;
+ BM_ITER_MESH_INDEX(f, &fiter, bm, BM_FACES_OF_MESH, index_face) {
+ BM_elem_index_set(f, index_face); /* set_inline */
+ l_curr = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_elem_index_set(l_curr, index_loop++); /* set_inline */
+ BM_elem_flag_disable(l_curr, BM_ELEM_TAG);
+ } while ((l_curr = l_curr->next) != l_first);
+ }
+ bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP);
+}
+
+/**
+* Auxillary function only used by rebuild to detect if any spaces were not marked as invalid.
+* Reports error if any of the lnor spaces change after rebuilding, meaning that all the possible
+* lnor spaces to be rebuilt were not correctly marked.
+*/
+#ifndef NDEBUG
+void BM_lnorspace_err(BMesh *bm)
+{
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ bool clear = true;
+
+ MLoopNorSpaceArray *temp = MEM_callocN(sizeof(*temp), __func__);
+ temp->lspacearr = NULL;
+
+ BKE_lnor_spacearr_init(temp, bm->totloop, MLNOR_SPACEARR_BMLOOP_PTR);
+
+ int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+ float(*lnors)[3] = MEM_callocN(sizeof(*lnors) * bm->totloop, __func__);
+ BM_loops_calc_normal_vcos(bm, NULL, NULL, NULL, true, M_PI, lnors, temp, NULL, cd_loop_clnors_offset, true);
+
+ for (int i = 0; i < bm->totloop; i++) {
+ int j = 0;
+ j += compare_ff(temp->lspacearr[i]->ref_alpha, bm->lnor_spacearr->lspacearr[i]->ref_alpha, 1e-4f);
+ j += compare_ff(temp->lspacearr[i]->ref_beta, bm->lnor_spacearr->lspacearr[i]->ref_beta, 1e-4f);
+ j += compare_v3v3(temp->lspacearr[i]->vec_lnor, bm->lnor_spacearr->lspacearr[i]->vec_lnor, 1e-4f);
+ j += compare_v3v3(temp->lspacearr[i]->vec_ortho, bm->lnor_spacearr->lspacearr[i]->vec_ortho, 1e-4f);
+ j += compare_v3v3(temp->lspacearr[i]->vec_ref, bm->lnor_spacearr->lspacearr[i]->vec_ref, 1e-4f);
+
+ if (j != 5) {
+ clear = false;
+ break;
+ }
+ }
+ BKE_lnor_spacearr_free(temp);
+ MEM_freeN(temp);
+ MEM_freeN(lnors);
+ BLI_assert(clear);
+
+ bm->spacearr_dirty &= ~BM_SPACEARR_DIRTY_ALL;
+}
+#endif
+
+static void bm_loop_normal_mark_indiv_do_loop(
+ BMLoop *l, BLI_bitmap *loops, MLoopNorSpaceArray *lnor_spacearr, int *totloopsel)
+{
+ if (l != NULL) {
+ const int l_idx = BM_elem_index_get(l);
+
+ if (!BLI_BITMAP_TEST(loops, BM_elem_index_get(l))) {
+ /* If vert and face selected share a loop, mark it for editing. */
+ BLI_BITMAP_ENABLE(loops, l_idx);
+ (*totloopsel)++;
+
+ /* Mark all loops in same loop normal space (aka smooth fan). */
+ if ((lnor_spacearr->lspacearr[l_idx]->flags & MLNOR_SPACE_IS_SINGLE) == 0) {
+ for (LinkNode *node = lnor_spacearr->lspacearr[l_idx]->loops; node; node = node->next) {
+ const int lfan_idx = BM_elem_index_get((BMLoop *)node->link);
+ if (!BLI_BITMAP_TEST(loops, lfan_idx)) {
+ BLI_BITMAP_ENABLE(loops, lfan_idx);
+ (*totloopsel)++;
+ }
}
- else if (mdisps->disps) {
- if (lmd->disps)
- MEM_freeN(lmd->disps);
+ }
+ }
+ }
+}
- lmd->disps = MEM_dupallocN(mdisps->disps);
- lmd->totdisp = mdisps->totdisp;
- lmd->level = mdisps->level;
+/* Mark the individual clnors to be edited, if multiple selection methods are used. */
+static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops)
+{
+ BMEditSelection *ese, *ese_prev;
+ int totloopsel = 0;
+
+ BM_mesh_elem_index_ensure(bm, BM_LOOP);
+
+ BLI_assert(bm->lnor_spacearr != NULL);
+ BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR);
+
+ /* Goes from last selected to the first selected element. */
+ for (ese = bm->selected.last; ese; ese = ese->prev) {
+ if (ese->htype == BM_FACE) {
+ ese_prev = ese;
+ /* If current face is selected, then any verts to be edited must have been selected before it. */
+ while ((ese_prev = ese_prev->prev)) {
+ if (ese_prev->htype == BM_VERT) {
+ bm_loop_normal_mark_indiv_do_loop(
+ BM_face_vert_share_loop((BMFace *)ese->ele, (BMVert *)ese_prev->ele),
+ loops, bm->lnor_spacearr, &totloopsel);
+ }
+ else if (ese_prev->htype == BM_EDGE) {
+ bm_loop_normal_mark_indiv_do_loop(
+ BM_face_vert_share_loop((BMFace *)ese->ele, ((BMEdge *)ese_prev->ele)->v1),
+ loops, bm->lnor_spacearr, &totloopsel);
+
+ bm_loop_normal_mark_indiv_do_loop(
+ BM_face_vert_share_loop((BMFace *)ese->ele, ((BMEdge *)ese_prev->ele)->v2),
+ loops, bm->lnor_spacearr, &totloopsel);
}
+ }
+ }
+ }
+
+ return totloopsel;
+}
+
+static void loop_normal_editdata_init(BMesh *bm, BMLoopNorEditData *lnor_ed, BMVert *v, BMLoop *l, const int offset)
+{
+ BLI_assert(bm->lnor_spacearr != NULL);
+ BLI_assert(bm->lnor_spacearr->lspacearr != NULL);
+
+ const int l_index = BM_elem_index_get(l);
+ short *clnors_data = BM_ELEM_CD_GET_VOID_P(l, offset);
+
+ lnor_ed->loop_index = l_index;
+ lnor_ed->loop = l;
+
+ float custom_normal[3];
+ BKE_lnor_space_custom_data_to_normal(bm->lnor_spacearr->lspacearr[l_index], clnors_data, custom_normal);
+
+ lnor_ed->clnors_data = clnors_data;
+ copy_v3_v3(lnor_ed->nloc, custom_normal);
+ copy_v3_v3(lnor_ed->niloc, custom_normal);
+
+ lnor_ed->loc = v->co;
+}
- mdisps++;
- // i += 1;
+BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm)
+{
+ BMLoop *l;
+ BMVert *v;
+ BMIter liter, viter;
+
+ bool verts = (bm->selectmode & SCE_SELECT_VERTEX) != 0;
+ bool edges = (bm->selectmode & SCE_SELECT_EDGE) != 0;
+ bool faces = (bm->selectmode & SCE_SELECT_FACE) != 0;
+ int totloopsel = 0;
+
+ BLI_assert(bm->spacearr_dirty == 0);
+
+ BMLoopNorEditDataArray *lnors_ed_arr = MEM_mallocN(
+ sizeof(*lnors_ed_arr), __func__);
+ lnors_ed_arr->lidx_to_lnor_editdata = MEM_callocN(
+ sizeof(*lnors_ed_arr->lidx_to_lnor_editdata) * bm->totloop, __func__);
+
+ if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ BM_data_layer_add(bm, &bm->ldata, CD_CUSTOMLOOPNORMAL);
+ }
+ const int cd_custom_normal_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+
+ BM_mesh_elem_index_ensure(bm, BM_LOOP);
+
+ BLI_bitmap *loops = BLI_BITMAP_NEW(bm->totloop, __func__);
+ if (faces && (verts || edges)) {
+ /* More than one selection mode, check for individual normals to edit. */
+ totloopsel = bm_loop_normal_mark_indiv(bm, loops);
+ }
+
+ if (totloopsel) {
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata = MEM_mallocN(sizeof(*lnor_ed) * totloopsel, __func__);
+
+ BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
+ BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
+ if (BLI_BITMAP_TEST(loops, BM_elem_index_get(l))) {
+ loop_normal_editdata_init(bm, lnor_ed, v, l, cd_custom_normal_offset);
+ lnors_ed_arr->lidx_to_lnor_editdata[BM_elem_index_get(l)] = lnor_ed;
+ lnor_ed++;
+ }
+ }
+ }
+ lnors_ed_arr->totloop = totloopsel;
+ }
+ else { /* If multiple selection modes are inactive OR no such loop is found, fall back to editing all loops. */
+ totloopsel = BM_total_loop_select(bm);
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata = MEM_mallocN(sizeof(*lnor_ed) * totloopsel, __func__);
+
+ BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
+ loop_normal_editdata_init(bm, lnor_ed, v, l, cd_custom_normal_offset);
+ lnors_ed_arr->lidx_to_lnor_editdata[BM_elem_index_get(l)] = lnor_ed;
+ lnor_ed++;
+ }
}
}
+ lnors_ed_arr->totloop = totloopsel;
+ }
+
+ MEM_freeN(loops);
+ lnors_ed_arr->cd_custom_normal_offset = cd_custom_normal_offset;
+ return lnors_ed_arr;
+}
+
+void BM_loop_normal_editdata_array_free(BMLoopNorEditDataArray *lnors_ed_arr)
+{
+ MEM_SAFE_FREE(lnors_ed_arr->lnor_editdata);
+ MEM_SAFE_FREE(lnors_ed_arr->lidx_to_lnor_editdata);
+ MEM_freeN(lnors_ed_arr);
+}
- dm->needsFree = 1;
- dm->release(dm);
+int BM_total_loop_select(BMesh *bm)
+{
+ int r_sel = 0;
+ BMVert *v;
+ BMIter viter;
- /* setting this to NULL prevents BKE_editmesh_free from freeing it */
- em->bm = NULL;
- BKE_editmesh_free(em);
- MEM_freeN(em);
+ BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ r_sel += BM_vert_face_count(v);
+ }
}
+ return r_sel;
}
/**
@@ -1141,6 +1525,7 @@ void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
/* compute normals, clear temp flags and flush selections */
if (type_flag & BMO_OPTYPE_FLAG_NORMALS_CALC) {
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
BM_mesh_normals_update(bm);
}
@@ -1157,9 +1542,12 @@ void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
if ((type_flag & BMO_OPTYPE_FLAG_SELECT_VALIDATE) == 0) {
bm->selected = select_history;
}
+ if (type_flag & BMO_OPTYPE_FLAG_INVALIDATE_CLNOR_ALL) {
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ }
}
-void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
+void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4])
{
const char htype_needed = bm->elem_index_dirty & htype;
@@ -1172,15 +1560,15 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
}
if (htype & BM_VERT) {
- if (bm->elem_index_dirty & BM_VERT) {
+ if ((bm->elem_index_dirty & BM_VERT) || (elem_offset && elem_offset[0])) {
BMIter iter;
BMElem *ele;
- int index;
- BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, index) {
- BM_elem_index_set(ele, index); /* set_ok */
+ int index = elem_offset ? elem_offset[0] : 0;
+ BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_index_set(ele, index++); /* set_ok */
}
- BLI_assert(index == bm->totvert);
+ BLI_assert(elem_offset || index == bm->totvert);
}
else {
// printf("%s: skipping vert index calc!\n", __func__);
@@ -1188,15 +1576,15 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
}
if (htype & BM_EDGE) {
- if (bm->elem_index_dirty & BM_EDGE) {
+ if ((bm->elem_index_dirty & BM_EDGE) || (elem_offset && elem_offset[1])) {
BMIter iter;
BMElem *ele;
- int index;
- BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, index) {
- BM_elem_index_set(ele, index); /* set_ok */
+ int index = elem_offset ? elem_offset[1] : 0;
+ BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_index_set(ele, index++); /* set_ok */
}
- BLI_assert(index == bm->totedge);
+ BLI_assert(elem_offset || index == bm->totedge);
}
else {
// printf("%s: skipping edge index calc!\n", __func__);
@@ -1204,19 +1592,19 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
}
if (htype & (BM_FACE | BM_LOOP)) {
- if (bm->elem_index_dirty & (BM_FACE | BM_LOOP)) {
+ if ((bm->elem_index_dirty & (BM_FACE | BM_LOOP)) || (elem_offset && (elem_offset[2] || elem_offset[3]))) {
BMIter iter;
BMElem *ele;
const bool update_face = (htype & BM_FACE) && (bm->elem_index_dirty & BM_FACE);
const bool update_loop = (htype & BM_LOOP) && (bm->elem_index_dirty & BM_LOOP);
- int index;
- int index_loop = 0;
+ int index_loop = elem_offset ? elem_offset[2] : 0;
+ int index = elem_offset ? elem_offset[3] : 0;
- BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, index) {
+ BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
if (update_face) {
- BM_elem_index_set(ele, index); /* set_ok */
+ BM_elem_index_set(ele, index++); /* set_ok */
}
if (update_loop) {
@@ -1229,9 +1617,9 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
}
}
- BLI_assert(index == bm->totface);
+ BLI_assert(elem_offset || !update_face || index == bm->totface);
if (update_loop) {
- BLI_assert(index_loop == bm->totloop);
+ BLI_assert(elem_offset || !update_loop || index_loop == bm->totloop);
}
}
else {
@@ -1241,6 +1629,37 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
finally:
bm->elem_index_dirty &= ~htype;
+ if (elem_offset) {
+ if (htype & BM_VERT) {
+ elem_offset[0] += bm->totvert;
+ if (elem_offset[0] != bm->totvert) {
+ bm->elem_index_dirty |= BM_VERT;
+ }
+ }
+ if (htype & BM_EDGE) {
+ elem_offset[1] += bm->totedge;
+ if (elem_offset[1] != bm->totedge) {
+ bm->elem_index_dirty |= BM_EDGE;
+ }
+ }
+ if (htype & BM_LOOP) {
+ elem_offset[2] += bm->totloop;
+ if (elem_offset[2] != bm->totloop) {
+ bm->elem_index_dirty |= BM_LOOP;
+ }
+ }
+ if (htype & BM_FACE) {
+ elem_offset[3] += bm->totface;
+ if (elem_offset[3] != bm->totface) {
+ bm->elem_index_dirty |= BM_FACE;
+ }
+ }
+ }
+}
+
+void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
+{
+ BM_mesh_elem_index_ensure_ex(bm, htype, NULL);
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index d449aac04f5..c7192590b79 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -29,6 +29,7 @@
struct BMAllocTemplate;
struct MLoopNorSpaceArray;
+struct BMLoopNorEditDataArray;
void BM_mesh_elem_toolflags_ensure(BMesh *bm);
void BM_mesh_elem_toolflags_clear(BMesh *bm);
@@ -48,11 +49,25 @@ void BM_mesh_clear(BMesh *bm);
void BM_mesh_normals_update(BMesh *bm);
void BM_verts_calc_normal_vcos(BMesh *bm, const float (*fnos)[3], const float (*vcos)[3], float (*vnos)[3]);
void BM_loops_calc_normal_vcos(
- BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*pnos)[3],
- const bool use_split_normals, const float split_angle, float (*r_lnos)[3],
- struct MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset);
+ BMesh *bm, const float(*vcos)[3], const float(*vnos)[3], const float(*pnos)[3],
+ const bool use_split_normals, const float split_angle, float(*r_lnos)[3],
+ struct MLoopNorSpaceArray *r_lnors_spacearr, short(*clnors_data)[2],
+ const int cd_loop_clnors_offset, const bool do_rebuild);
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr);
+void BM_lnorspacearr_store(BMesh *bm, float(*r_lnors)[3]);
+void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all);
+void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor);
+void BM_lnorspace_update(BMesh *bm);
+void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges);
+#ifndef NDEBUG
+void BM_lnorspace_err(BMesh *bm);
+#endif
+
+/* Loop Generics */
+struct BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm);
+void BM_loop_normal_editdata_array_free(struct BMLoopNorEditDataArray *lnors_ed_arr);
+int BM_total_loop_select(BMesh *bm);
void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle);
@@ -60,6 +75,7 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle);
void bmesh_edit_begin(BMesh *bm, const BMOpTypeFlag type_flag);
void bmesh_edit_end(BMesh *bm, const BMOpTypeFlag type_flag);
+void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4]);
void BM_mesh_elem_index_ensure(BMesh *bm, const char hflag);
void BM_mesh_elem_index_validate(
BMesh *bm, const char *location, const char *func,
@@ -110,25 +126,22 @@ extern const BMAllocTemplate bm_mesh_chunksize_default;
#define BMALLOC_TEMPLATE_FROM_BM(bm) { (CHECK_TYPE_INLINE(bm, BMesh *), \
(bm)->totvert), (bm)->totedge, (bm)->totloop, (bm)->totface}
-#define BMALLOC_TEMPLATE_FROM_ME(me) { (CHECK_TYPE_INLINE(me, Mesh *), \
- (me)->totvert), (me)->totedge, (me)->totloop, (me)->totpoly}
-
-#define _VA_BMALLOC_TEMPLATE_FROM_DM_1(dm) { \
- (CHECK_TYPE_INLINE(dm, DerivedMesh *), \
- (dm)->getNumVerts(dm)), \
- (dm)->getNumEdges(dm), \
- (dm)->getNumLoops(dm), \
- (dm)->getNumPolys(dm), \
+
+#define _VA_BMALLOC_TEMPLATE_FROM_ME_1(me) { \
+ (CHECK_TYPE_INLINE(me, Mesh *), \
+ (me)->totvert), \
+ (me)->totedge, \
+ (me)->totloop, \
+ (me)->totpoly, \
}
-#define _VA_BMALLOC_TEMPLATE_FROM_DM_2(dm_a, dm_b) { \
- (CHECK_TYPE_INLINE(dm_a, DerivedMesh *), \
- CHECK_TYPE_INLINE(dm_b, DerivedMesh *), \
- (dm_a)->getNumVerts(dm_a)) + (dm_b)->getNumVerts(dm_b), \
- (dm_a)->getNumEdges(dm_a) + (dm_b)->getNumEdges(dm_b), \
- (dm_a)->getNumLoops(dm_a) + (dm_b)->getNumLoops(dm_b), \
- (dm_a)->getNumPolys(dm_a) + (dm_b)->getNumPolys(dm_b), \
+#define _VA_BMALLOC_TEMPLATE_FROM_ME_2(me_a, me_b) { \
+ (CHECK_TYPE_INLINE(me_a, Mesh *), \
+ CHECK_TYPE_INLINE(me_b, Mesh *), \
+ (me_a)->totvert + (me_b)->totvert), \
+ (me_a)->totedge + (me_b)->totedge, \
+ (me_a)->totloop + (me_b)->totloop, \
+ (me_a)->totpoly + (me_b)->totpoly, \
}
-
-#define BMALLOC_TEMPLATE_FROM_DM(...) VA_NARGS_CALL_OVERLOAD(_VA_BMALLOC_TEMPLATE_FROM_DM_, __VA_ARGS__)
+#define BMALLOC_TEMPLATE_FROM_ME(...) VA_NARGS_CALL_OVERLOAD(_VA_BMALLOC_TEMPLATE_FROM_ME_, __VA_ARGS__)
#endif /* __BMESH_MESH_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index 340b0b70772..7e1e1c53a8f 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -88,6 +88,7 @@
#include "BLI_math_vector.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_customdata.h"
#include "BKE_multires.h"
@@ -98,42 +99,6 @@
#include "bmesh.h"
#include "intern/bmesh_private.h" /* for element checking */
-/**
- * Currently this is only used for Python scripts
- * which may fail to keep matching UV/TexFace layers.
- *
- * \note This should only perform any changes in exceptional cases,
- * if we need this to be faster we could inline #BM_data_layer_add and only
- * call #update_data_blocks once at the end.
- */
-void BM_mesh_cd_validate(BMesh *bm)
-{
- int totlayer_mtex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
- int totlayer_uv = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
-
- if (LIKELY(totlayer_mtex == totlayer_uv)) {
- /* pass */
- }
- else if (totlayer_mtex < totlayer_uv) {
- const int uv_index_first = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
- do {
- const char *from_name = bm->ldata.layers[uv_index_first + totlayer_mtex].name;
- BM_data_layer_add_named(bm, &bm->pdata, CD_MTEXPOLY, from_name);
- CustomData_set_layer_unique_name(&bm->pdata, totlayer_mtex);
- } while (totlayer_uv != ++totlayer_mtex);
- }
- else if (totlayer_uv < totlayer_mtex) {
- const int mtex_index_first = CustomData_get_layer_index(&bm->pdata, CD_MTEXPOLY);
- do {
- const char *from_name = bm->pdata.layers[mtex_index_first + totlayer_uv].name;
- BM_data_layer_add_named(bm, &bm->ldata, CD_MLOOPUV, from_name);
- CustomData_set_layer_unique_name(&bm->ldata, totlayer_uv);
- } while (totlayer_mtex != ++totlayer_uv);
- }
-
- BLI_assert(totlayer_mtex == totlayer_uv);
-}
-
void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag)
{
const char cd_flag_all = BM_mesh_cd_flag_from_bmesh(bm) | cd_flag;
@@ -243,7 +208,7 @@ void BM_mesh_bm_from_me(
BMEdge *e, **etable = NULL;
BMFace *f, **ftable = NULL;
float (*keyco)[3] = NULL;
- int totuv, totloops, i;
+ int totloops, i;
if (!me || !me->totvert) {
if (me && is_new) { /*no verts? still copy customdata layout*/
@@ -265,13 +230,6 @@ void BM_mesh_bm_from_me(
CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
-
- /* make sure uv layer names are consisten */
- totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
- for (i = 0; i < totuv; i++) {
- int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i);
- CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name);
- }
}
/* -------------------------------------------------------------------- */
@@ -592,7 +550,7 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
/**
*
- * \param bmain May be NULL in case \a calc_object_remap parameter option is set.
+ * \param bmain May be NULL in case \a calc_object_remap parameter option is not set.
*/
void BM_mesh_bm_to_me(
Main *bmain, BMesh *bm, Mesh *me,
@@ -984,4 +942,7 @@ void BM_mesh_bm_to_me(
/* topology could be changed, ensure mdisps are ok */
multires_topology_changed(me);
+
+ /* to be removed as soon as COW is enabled by default. */
+ BKE_mesh_runtime_clear_geometry(me);
}
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index b5e6fe168e5..ef9c510aea1 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1736,12 +1736,17 @@ static BMOpDefine bmo_bevel_def = {
{"clamp_overlap", BMO_OP_SLOT_BOOL}, /* do not allow beveled edges/vertices to overlap each other */
{"material", BMO_OP_SLOT_INT}, /* material for bevel faces, -1 means get from adjacent faces */
{"loop_slide", BMO_OP_SLOT_BOOL}, /* prefer to slide along edges to having even widths */
+ {"mark_seam", BMO_OP_SLOT_BOOL}, /* extend edge data to allow seams to run across bevels */
+ {"mark_sharp", BMO_OP_SLOT_BOOL}, /* extend edge data to allow sharp edges to run across bevels */
+ {"strength", BMO_OP_SLOT_FLT}, /* strength of calculated normal in range (0, 1) for custom clnors */
+ {"hnmode", BMO_OP_SLOT_INT}, /* harden normals mode used in bevel if enabled */
{{'\0'}},
},
/* slots_out */
{{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* output faces */
{"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* output edges */
{"verts.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* output verts */
+ {"normals.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, /* output normals per vertex for beveled edges */
{{'\0'}},
},
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index 30cd1df9c4e..de87da71e8d 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -244,6 +244,7 @@ typedef enum {
BMO_OPTYPE_FLAG_NORMALS_CALC = (1 << 1),
BMO_OPTYPE_FLAG_SELECT_FLUSH = (1 << 2),
BMO_OPTYPE_FLAG_SELECT_VALIDATE = (1 << 3),
+ BMO_OPTYPE_FLAG_INVALIDATE_CLNOR_ALL = (1 << 4),
} BMOpTypeFlag;
typedef struct BMOperator {
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index b670f31ad9f..6d518545967 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -77,13 +77,13 @@ enum {
/* similar face selection slot values */
enum {
SIMFACE_MATERIAL = 201,
- SIMFACE_IMAGE,
SIMFACE_AREA,
SIMFACE_SIDES,
SIMFACE_PERIMETER,
SIMFACE_NORMAL,
SIMFACE_COPLANAR,
SIMFACE_SMOOTH,
+ SIMFACE_FACEMAP,
#ifdef WITH_FREESTYLE
SIMFACE_FREESTYLE
#endif
@@ -127,6 +127,13 @@ enum {
BEVEL_AMT_PERCENT
};
+enum {
+ BEVEL_HN_NONE, /* Disable harden normals */
+ BEVEL_HN_FACE, /* harden normals according to face area */
+ BEVEL_HN_ADJ, /* harden normals according to adjacent 'beveled' faces */
+ BEVEL_HN_FIX_SHA, /* Special mode to fix normal shading continuity */
+};
+
extern const BMOpDefine *bmo_opdefines[];
extern const int bmo_opdefines_total;
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 7cbc6461667..421b2adc3a7 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -487,7 +487,7 @@ void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3])
}
/**
- * Compute a meaningful direction along the face (use for manipulator axis).
+ * Compute a meaningful direction along the face (use for gizmo axis).
*
* \note Callers shouldn't depend on the *exact* method used here.
*/
diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c
index 2ae87b64286..8bc219d8421 100644
--- a/source/blender/bmesh/operators/bmo_bevel.c
+++ b/source/blender/bmesh/operators/bmo_bevel.c
@@ -43,6 +43,9 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
const bool clamp_overlap = BMO_slot_bool_get(op->slots_in, "clamp_overlap");
const int material = BMO_slot_int_get(op->slots_in, "material");
const bool loop_slide = BMO_slot_bool_get(op->slots_in, "loop_slide");
+ const bool mark_seam = BMO_slot_bool_get(op->slots_in, "mark_seam");
+ const bool mark_sharp = BMO_slot_bool_get(op->slots_in, "mark_sharp");
+ const int hnmode = BMO_slot_int_get(op->slots_in, "hnmode");
if (offset > 0) {
BMOIter siter;
@@ -63,7 +66,9 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
}
}
- BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, clamp_overlap, NULL, -1, material, loop_slide);
+ BM_mesh_bevel(
+ bm, offset, offset_type, seg, profile, vonly, false, clamp_overlap, NULL, -1, material,
+ loop_slide, mark_seam, mark_sharp, hnmode, op);
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG);
diff --git a/source/blender/bmesh/operators/bmo_similar.c b/source/blender/bmesh/operators/bmo_similar.c
index 454d6d8c6c8..0cd17258834 100644
--- a/source/blender/bmesh/operators/bmo_similar.c
+++ b/source/blender/bmesh/operators/bmo_similar.c
@@ -106,11 +106,28 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
const float thresh = BMO_slot_float_get(op->slots_in, "thresh");
const float thresh_radians = thresh * (float)M_PI;
const int compare = BMO_slot_int_get(op->slots_in, "compare");
+ /* for comparison types that use custom-data */
+ int cd_offset = -1;
/* initial_elem - other_elem */
float delta_fl;
int delta_i;
+ if (type == SIMFACE_FACEMAP) {
+ cd_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP);
+ if (cd_offset == -1) {
+ return;
+ }
+ }
+#ifdef WITH_FREESTYLE
+ else if (type == SIMFACE_FREESTYLE) {
+ cd_offset = CustomData_get_offset(&bm->pdata, CD_FREESTYLE_FACE);
+ if (cd_offset == -1) {
+ return;
+ }
+ }
+#endif
+
num_total = BM_mesh_elem_count(bm, BM_FACE);
/*
@@ -145,7 +162,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
* Save us some computation burden: In case of perimeter/area/coplanar selection we compute
* only once.
*/
- if (type == SIMFACE_PERIMETER || type == SIMFACE_AREA || type == SIMFACE_COPLANAR || type == SIMFACE_IMAGE) {
+ if (type == SIMFACE_PERIMETER || type == SIMFACE_AREA || type == SIMFACE_COPLANAR) {
for (i = 0; i < num_total; i++) {
switch (type) {
case SIMFACE_PERIMETER:
@@ -164,14 +181,6 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
case SIMFACE_AREA:
f_ext[i].area = BM_face_calc_area(f_ext[i].f);
break;
-
- case SIMFACE_IMAGE:
- f_ext[i].t = NULL;
- if (CustomData_has_layer(&(bm->pdata), CD_MTEXPOLY)) {
- MTexPoly *mtpoly = CustomData_bmesh_get(&bm->pdata, f_ext[i].f->head.data, CD_MTEXPOLY);
- f_ext[i].t = mtpoly->tpage;
- }
- break;
}
}
}
@@ -190,14 +199,6 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
cont = false;
}
break;
-
- case SIMFACE_IMAGE:
- if (f_ext[i].t == f_ext[indices[idx]].t) {
- BMO_face_flag_enable(bm, fm, FACE_MARK);
- cont = false;
- }
- break;
-
case SIMFACE_NORMAL:
angle = angle_normalized_v3v3(fs->no, fm->no); /* if the angle between the normals -> 0 */
if (angle <= thresh_radians) {
@@ -254,20 +255,29 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
cont = false;
}
break;
+ case SIMFACE_FACEMAP:
+ {
+ BLI_assert(cd_offset != -1);
+ const int *fmap1 = BM_ELEM_CD_GET_VOID_P(fs, cd_offset);
+ const int *fmap2 = BM_ELEM_CD_GET_VOID_P(fm, cd_offset);
+ if (*fmap1 == *fmap2) {
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
+ cont = false;
+ }
+ break;
+ }
#ifdef WITH_FREESTYLE
case SIMFACE_FREESTYLE:
- if (CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE)) {
- FreestyleEdge *ffa1, *ffa2;
-
- ffa1 = CustomData_bmesh_get(&bm->pdata, fs->head.data, CD_FREESTYLE_FACE);
- ffa2 = CustomData_bmesh_get(&bm->pdata, fm->head.data, CD_FREESTYLE_FACE);
-
- if (ffa1 && ffa2 && (ffa1->flag & FREESTYLE_FACE_MARK) == (ffa2->flag & FREESTYLE_FACE_MARK)) {
- BMO_face_flag_enable(bm, fm, FACE_MARK);
- cont = false;
- }
+ {
+ BLI_assert(cd_offset != -1);
+ const FreestyleEdge *ffa1 = BM_ELEM_CD_GET_VOID_P(fs, cd_offset);
+ const FreestyleEdge *ffa2 = BM_ELEM_CD_GET_VOID_P(fm, cd_offset);
+ if ((ffa1->flag & FREESTYLE_FACE_MARK) == (ffa2->flag & FREESTYLE_FACE_MARK)) {
+ BMO_face_flag_enable(bm, fm, FACE_MARK);
+ cont = false;
}
break;
+ }
#endif
default:
BLI_assert(0);
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index adfcb8dc68f..90e4033d572 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -34,6 +34,7 @@
#include "DNA_object_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "BLI_array.h"
#include "BLI_alloca.h"
@@ -43,6 +44,7 @@
#include "BKE_customdata.h"
#include "BKE_deform.h"
+#include "BKE_mesh.h"
#include "eigen_capi.h"
@@ -150,6 +152,8 @@ typedef struct BoundVert {
Profile profile; /* edge profile between this and next BoundVert */
bool any_seam; /* are any of the edges attached here seams? */
bool visited; /* used during delta adjust pass */
+ int seam_len; /* length of seam starting from current boundvert to next boundvert with ccw ordering */
+ int sharp_len; /* Same as seam_len but defines length of sharp edges */
// int _pad;
} BoundVert;
@@ -188,6 +192,8 @@ typedef struct BevelParams {
/* hash of BevVert for each vertex involved in bevel
* GHash: (key=(BMVert *), value=(BevVert *)) */
GHash *vert_hash;
+ /* Hash set used to store resultant beveled faces for VMesh when poly is ring */
+ GHash *faceHash;
MemArena *mem_arena; /* use for all allocs while bevel runs, if we need to free we can switch to mempool */
ProfileSpacing pro_spacing; /* parameter values for evenly spaced profiles */
@@ -200,9 +206,12 @@ typedef struct BevelParams {
bool loop_slide; /* should bevel prefer to slide along edges rather than keep widths spec? */
bool limit_offset; /* should offsets be limited by collisions? */
bool offset_adjust; /* should offsets be adjusted to try to get even widths? */
+ bool mark_seam;
+ bool mark_sharp;
const struct MDeformVert *dvert; /* vertex group array, maybe set if vertex_only */
int vertex_group; /* vertex group index, maybe set if vertex_only */
int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */
+ int hnmode;
} BevelParams;
// #pragma GCC diagnostic ignored "-Wpadded"
@@ -767,6 +776,11 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
sub_v3_v3v3(dir1n, BM_edge_other_vert(e1next->e, v)->co, v->co);
sub_v3_v3v3(dir2p, v->co, BM_edge_other_vert(e2prev->e, v)->co);
}
+ else {
+ /* shup up 'maybe unused' warnings */
+ zero_v3(dir1n);
+ zero_v3(dir2p);
+ }
ang = angle_v3v3(dir1, dir2);
if (ang < BEVEL_EPSILON_ANG) {
@@ -1522,8 +1536,219 @@ static void snap_to_superellipsoid(float co[3], const float super_r, bool midlin
co[2] = z;
}
+#define BEV_EXTEND_EDGE_DATA_CHECK(eh, flag) (BM_elem_flag_test(eh->e, flag))
+
+static void check_edge_data_seam_sharp_edges(BevVert *bv, int flag, bool neg)
+{
+ EdgeHalf *e = &bv->edges[0], *efirst = &bv->edges[0];
+
+ /* First first edge with seam or sharp edge data */
+ while ((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(e, flag)) || (neg && BEV_EXTEND_EDGE_DATA_CHECK(e, flag))) {
+ e = e->next;
+ if (e == efirst)
+ break;
+ }
+
+ /* If no such edge found, return */
+ if ((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(e, flag)) || (neg && BEV_EXTEND_EDGE_DATA_CHECK(e, flag)))
+ return;
+
+ /* Set efirst to this first encountered edge. */
+ efirst = e;
+
+ do {
+ int flag_count = 0;
+ EdgeHalf *ne = e->next;
+
+ while (((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(ne, flag)) || (neg && BEV_EXTEND_EDGE_DATA_CHECK(ne, flag))) &&
+ ne != efirst)
+ {
+ if (ne->is_bev)
+ flag_count++;
+ ne = ne->next;
+ }
+ if (ne == e || (ne == efirst && ((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(efirst, flag)) ||
+ (neg && BEV_EXTEND_EDGE_DATA_CHECK(efirst, flag)))))
+ {
+ break;
+ }
+ /* Set seam_len / sharp_len of starting edge */
+ if (flag == BM_ELEM_SEAM) {
+ e->rightv->seam_len = flag_count;
+ }
+ else if (flag == BM_ELEM_SMOOTH) {
+ e->rightv->sharp_len = flag_count;
+ }
+ e = ne;
+ } while (e != efirst);
+}
+
+static void bevel_extend_edge_data(BevVert *bv)
+{
+ VMesh *vm = bv->vmesh;
+
+ BoundVert *bcur = bv->vmesh->boundstart, *start = bcur;
+
+ do {
+ /* If current boundvert has a seam length > 0 then it has a seam running along its edges */
+ if (bcur->seam_len) {
+ if (!bv->vmesh->boundstart->seam_len && start == bv->vmesh->boundstart)
+ start = bcur; /* set start to first boundvert with seam_len > 0 */
+
+ /* Now for all the mesh_verts starting at current index and ending at idxlen
+ * We go through outermost ring and through all its segments and add seams
+ * for those edges */
+ int idxlen = bcur->index + bcur->seam_len;
+ for (int i = bcur->index; i < idxlen; i++) {
+ BMVert *v1 = mesh_vert(vm, i % vm->count, 0, 0)->v, *v2;
+ BMEdge *e;
+ for (int k = 1; k < vm->seg; k++) {
+ v2 = mesh_vert(vm, i % vm->count, 0, k)->v;
+
+ /* Here v1 & v2 are current and next BMverts, we find common edge and set its edge data */
+ e = v1->e;
+ while (e->v1 != v2 && e->v2 != v2) {
+ if (e->v1 == v1)
+ e = e->v1_disk_link.next;
+ else
+ e = e->v2_disk_link.next;
+ }
+ BM_elem_flag_set(e, BM_ELEM_SEAM, true);
+ v1 = v2;
+ }
+ BMVert *v3 = mesh_vert(vm, (i + 1) % vm->count, 0, 0)->v;
+ e = v1->e; //Do same as above for first and last vert
+ while (e->v1 != v3 && e->v2 != v3) {
+ if (e->v1 == v1)
+ e = e->v1_disk_link.next;
+ else
+ e = e->v2_disk_link.next;
+ }
+ BM_elem_flag_set(e, BM_ELEM_SEAM, true);
+ bcur = bcur->next;
+ }
+ }
+ else
+ bcur = bcur->next;
+ } while (bcur != start);
+
+
+ bcur = bv->vmesh->boundstart;
+ start = bcur;
+ do {
+ if (bcur->sharp_len) {
+ if (!bv->vmesh->boundstart->sharp_len && start == bv->vmesh->boundstart)
+ start = bcur;
+
+ int idxlen = bcur->index + bcur->sharp_len;
+ for (int i = bcur->index; i < idxlen; i++) {
+ BMVert *v1 = mesh_vert(vm, i % vm->count, 0, 0)->v, *v2;
+ BMEdge *e;
+ for (int k = 1; k < vm->seg; k++) {
+ v2 = mesh_vert(vm, i % vm->count, 0, k)->v;
+
+ e = v1->e;
+ while (e->v1 != v2 && e->v2 != v2) {
+ if (e->v1 == v1)
+ e = e->v1_disk_link.next;
+ else
+ e = e->v2_disk_link.next;
+ }
+ BM_elem_flag_set(e, BM_ELEM_SMOOTH, false);
+ v1 = v2;
+ }
+ BMVert *v3 = mesh_vert(vm, (i + 1) % vm->count, 0, 0)->v;
+ e = v1->e;
+ while (e->v1 != v3 && e->v2 != v3) {
+ if (e->v1 == v1)
+ e = e->v1_disk_link.next;
+ else
+ e = e->v2_disk_link.next;
+ }
+ BM_elem_flag_set(e, BM_ELEM_SMOOTH, false);
+ bcur = bcur->next;
+ }
+ }
+ else
+ bcur = bcur->next;
+ } while (bcur != start);
+}
+
+static void bevel_harden_normals_mode(BevelParams *bp, BevVert *bv, BMOperator *op)
+{
+ if (bp->hnmode == BEVEL_HN_NONE)
+ return;
+
+ VMesh *vm = bv->vmesh;
+ BoundVert *bcur = vm->boundstart, *bstart = bcur;
+
+ BMEdge *e;
+ BMIter eiter;
+
+ BMOpSlot *nslot = BMO_slot_get(op->slots_out, "normals.out");
+ float n_final[3] = { 0.0f, 0.0f, 0.0f };
+
+ if (bp->hnmode == BEVEL_HN_FACE) {
+ GHash *tempfaceHash = BLI_ghash_int_new(__func__);
+
+ /* Iterate through all faces of current BMVert and add their normal*face_area to n_final */
+ BM_ITER_ELEM(e, &eiter, bv->v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+
+ BMFace *f_a, *f_b;
+ BM_edge_face_pair(e, &f_a, &f_b);
+
+ if (f_a && !BLI_ghash_haskey(tempfaceHash, SET_UINT_IN_POINTER(BM_elem_index_get(f_a)))) {
+ int f_area = BM_face_calc_area(f_a);
+ float f_no[3];
+ copy_v3_v3(f_no, f_a->no);
+ mul_v3_fl(f_no, f_area);
+ add_v3_v3(n_final, f_no);
+ BLI_ghash_insert(tempfaceHash, SET_UINT_IN_POINTER(BM_elem_index_get(f_a)), NULL);
+ }
+ if (f_b && !BLI_ghash_haskey(tempfaceHash, SET_UINT_IN_POINTER(BM_elem_index_get(f_b)))) {
+ int f_area = BM_face_calc_area(f_b);
+ float f_no[3];
+ copy_v3_v3(f_no, f_b->no);
+ mul_v3_fl(f_no, f_area);
+ add_v3_v3(n_final, f_no);
+ BLI_ghash_insert(tempfaceHash, SET_UINT_IN_POINTER(BM_elem_index_get(f_b)), NULL);
+ }
+ }
+ }
+ BLI_ghash_free(tempfaceHash, NULL, NULL);
+ normalize_v3(n_final);
+ }
+ else if (bp->hnmode == BEVEL_HN_ADJ) {
+ BM_ITER_ELEM(e, &eiter, bv->v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ if (e->v1 == bv->v) {
+ add_v3_v3(n_final, e->v2->no);
+ }
+ else {
+ add_v3_v3(n_final, e->v1->no);
+ }
+ }
+ }
+ normalize_v3(n_final);
+ }
+
+ do {
+ /* Set normals.out for vertices as computed earlier */
+ if (BMO_slot_map_contains(nslot, bcur->nv.v) != true) {
+
+ float(*vert_normal) = MEM_callocN(sizeof(*vert_normal) * 3, __func__);
+ add_v3_v3(vert_normal, n_final);
+ normalize_v3(vert_normal);
+
+ BMO_slot_map_insert(op, nslot, bcur->nv.v, vert_normal);
+ }
+ bcur = bcur->next;
+ } while (bcur != bstart);
+}
+
/* Set the any_seam property for a BevVert and all its BoundVerts */
-static void set_bound_vert_seams(BevVert *bv)
+static void set_bound_vert_seams(BevVert *bv, bool mark_seam, bool mark_sharp)
{
BoundVert *v;
EdgeHalf *e;
@@ -1539,6 +1764,13 @@ static void set_bound_vert_seams(BevVert *bv)
}
bv->any_seam |= v->any_seam;
} while ((v = v->next) != bv->vmesh->boundstart);
+
+ if (mark_seam) {
+ check_edge_data_seam_sharp_edges(bv, BM_ELEM_SEAM, false);
+ }
+ if (mark_sharp) {
+ check_edge_data_seam_sharp_edges(bv, BM_ELEM_SMOOTH, true);
+ }
}
static int count_bound_vert_seams(BevVert *bv)
@@ -1609,7 +1841,7 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr
calculate_vm_profiles(bp, bv, vm);
if (construct) {
- set_bound_vert_seams(bv);
+ set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
if (vm->count == 2)
vm->mesh_kind = M_NONE;
else if (bp->seg == 1)
@@ -1664,7 +1896,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
e->next->leftv = e->next->rightv = v;
/* could use M_POLY too, but tri-fan looks nicer)*/
vm->mesh_kind = M_TRI_FAN;
- set_bound_vert_seams(bv);
+ set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
}
else {
adjust_bound_vert(e->next->leftv, co);
@@ -1723,7 +1955,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
}
if (construct) {
- set_bound_vert_seams(bv);
+ set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
if (vm->count == 2 && bv->edgecount == 3) {
vm->mesh_kind = M_NONE;
@@ -1865,7 +2097,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
calculate_vm_profiles(bp, bv, vm);
if (construct) {
- set_bound_vert_seams(bv);
+ set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
if (vm->count == 2) {
vm->mesh_kind = M_NONE;
@@ -2919,29 +3151,36 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp)
}
/* Is this a good candidate for using tri_corner_adj_vmesh? */
-static bool tri_corner_test(BevelParams *bp, BevVert *bv)
+static int tri_corner_test(BevelParams *bp, BevVert *bv)
{
float ang, totang, angdiff;
EdgeHalf *e;
int i;
+ int in_plane_e = 0;
- if (bv->edgecount != 3 || bv->selcount != 3)
- return false;
+ if (bp->vertex_only)
+ return -1;
totang = 0.0f;
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < bv->edgecount; i++) {
e = &bv->edges[i];
ang = BM_edge_calc_face_angle_signed_ex(e->e, 0.0f);
- if (ang <= (float) M_PI_4 || ang >= 3.0f * (float) M_PI_4)
- return false;
+ if (ang <= M_PI_4)
+ in_plane_e++;
+ else if (ang >= 3.0f * (float) M_PI_4)
+ return -1;
totang += ang;
}
+ if (in_plane_e != bv->edgecount - 3)
+ return -1;
angdiff = fabsf(totang - 3.0f * (float)M_PI_2);
if ((bp->pro_super_r == PRO_SQUARE_R && angdiff > (float)M_PI / 16.0f) ||
(angdiff > (float)M_PI_4))
{
- return false;
+ return -1;
}
- return true;
+ if (bv->edgecount != 3 || bv->selcount != 3)
+ return 0;
+ return 1;
}
static VMesh *tri_corner_adj_vmesh(BevelParams *bp, BevVert *bv)
@@ -2952,7 +3191,7 @@ static VMesh *tri_corner_adj_vmesh(BevelParams *bp, BevVert *bv)
VMesh *vm;
BoundVert *bndv;
- BLI_assert(bv->edgecount == 3 && bv->selcount == 3);
+ /*BLI_assert(bv->edgecount == 3 && bv->selcount == 3); Add support for in plane edges */
bndv = bv->vmesh->boundstart;
copy_v3_v3(co0, bndv->nv.co);
bndv = bndv->next;
@@ -2985,9 +3224,14 @@ static VMesh *adj_vmesh(BevelParams *bp, BevVert *bv)
BoundVert *bndv;
MemArena *mem_arena = bp->mem_arena;
float r, fac, fullness;
+ n = bv->vmesh->count;
+
+ /* Same bevel as that of 3 edges of vert in a cube */
+ if (n == 3 && tri_corner_test(bp, bv) != -1 && bp->pro_super_r != PRO_SQUARE_IN_R) {
+ return tri_corner_adj_vmesh(bp, bv);
+ }
/* First construct an initial control mesh, with nseg==2 */
- n = bv->vmesh->count;
ns = bv->vmesh->seg;
vm0 = new_adj_vmesh(mem_arena, n, 2, bv->vmesh->boundstart);
@@ -3430,7 +3674,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
VMesh *vm1, *vm;
BoundVert *v;
BMVert *bmv1, *bmv2, *bmv3, *bmv4;
- BMFace *f, *f2;
+ BMFace *f, *f2, *r_f;
BMEdge *bme, *bme1, *bme2, *bme3;
EdgeHalf *e;
BoundVert *vpipe;
@@ -3442,6 +3686,17 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
odd = ns % 2;
BLI_assert(n >= 3 && ns > 1);
+ /* Add support for profiles in vertex only in-plane bevels */
+ if (bp->vertex_only) {
+ v = bv->vmesh->boundstart;
+ do {
+ Profile *pro = &v->profile;
+ pro->super_r = bp->pro_super_r;
+ copy_v3_v3(pro->midco, bv->v->co);
+ calculate_profile(bp, v);
+ v = v->next;
+ } while (v != bv->vmesh->boundstart);
+ }
vpipe = pipe_test(bv);
@@ -3451,7 +3706,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
else if (vpipe) {
vm1 = pipe_adj_vmesh(bp, bv, vpipe);
}
- else if (tri_corner_test(bp, bv)) {
+ else if (tri_corner_test(bp, bv) == 1) {
vm1 = tri_corner_adj_vmesh(bp, bv);
/* the PRO_SQUARE_IN_R profile has boundary edges that merge
* and no internal ring polys except possibly center ngon */
@@ -3464,6 +3719,8 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
vm1 = adj_vmesh(bp, bv);
}
+ bool do_fix_shading_bv = bp->faceHash != NULL;
+
/* copy final vmesh into bv->vmesh, make BMVerts and BMFaces */
vm = bv->vmesh;
for (i = 0; i < n; i++) {
@@ -3505,24 +3762,24 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
if (bp->vertex_only) {
if (j < k) {
if (k == ns2 && j == ns2 - 1) {
- bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2,
+ r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2,
NULL, NULL, v->next->efirst->e, bme, mat_nr);
}
else {
- bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
+ r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
}
}
else if (j > k) {
- bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
+ r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
}
else { /* j == k */
/* only one edge attached to v, since vertex_only */
if (e->is_seam) {
- bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2,
+ r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2,
bme, NULL, bme, NULL, mat_nr);
}
else {
- bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f,
+ r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f,
bme, NULL, bme, NULL, mat_nr);
}
}
@@ -3531,25 +3788,27 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
if (odd) {
if (k == ns2) {
if (e->is_seam) {
- bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f,
+ r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f,
NULL, bme, bme, NULL, mat_nr);
}
else {
- bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f2, f2, f, mat_nr);
+ r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f2, f2, f, mat_nr);
}
}
else {
- bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, mat_nr);
+ r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, mat_nr);
}
}
else {
bme1 = k == ns2 - 1 ? bme : NULL;
bme3 = j == ns2 - 1 ? v->prev->ebev->e : NULL;
bme2 = bme1 != NULL ? bme1 : bme3;
- bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f,
+ r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f,
NULL, bme1, bme2, bme3, mat_nr);
}
}
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, r_f, NULL);
}
}
} while ((v = v->next) != vm->boundstart);
@@ -3622,6 +3881,8 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv)
BLI_array_staticdeclare(vf, BM_DEFAULT_NGON_STACK_SIZE);
BLI_array_staticdeclare(ve, BM_DEFAULT_NGON_STACK_SIZE);
+ bool do_fix_shading_bv = bp->faceHash != NULL;
+
if (bv->any_seam) {
frep = boundvert_rep_face(vm->boundstart, &frep2);
if (frep2 && frep && is_bad_uv_poly(bv, frep)) {
@@ -3667,6 +3928,8 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv)
} while ((v = v->next) != vm->boundstart);
if (n > 2) {
f = bev_create_ngon(bm, vv, n, vf, frep, ve, bp->mat_nr, true);
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, f, NULL);
}
else {
f = NULL;
@@ -3681,6 +3944,7 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv)
{
BMFace *f;
BLI_assert(next_bev(bv, NULL)->seg == 1 || bv->selcount == 1);
+ bool do_fix_shading_bv = bp->faceHash != NULL;
f = bevel_build_poly(bp, bm, bv);
@@ -3689,6 +3953,11 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv)
BMLoop *l_fan = BM_FACE_FIRST_LOOP(f)->prev;
BMVert *v_fan = l_fan->v;
+ if (f->len == 3) {
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, f, NULL);
+ }
+
while (f->len > 3) {
BMLoop *l_new;
BMFace *f_new;
@@ -3709,6 +3978,8 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv)
else if (l_fan->prev->v == v_fan) { l_fan = l_fan->prev; }
else { BLI_assert(0); }
}
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, f_new, NULL);
}
}
}
@@ -3717,6 +3988,7 @@ static void bevel_build_quadstrip(BevelParams *bp, BMesh *bm, BevVert *bv)
{
BMFace *f;
BLI_assert(bv->selcount == 2);
+ bool do_fix_shading_bv = bp->faceHash != NULL;
f = bevel_build_poly(bp, bm, bv);
@@ -3728,6 +4000,11 @@ static void bevel_build_quadstrip(BevelParams *bp, BMesh *bm, BevVert *bv)
BMLoop *l_b = BM_face_vert_share_loop(f, eh_b->leftv->nv.v);
int split_count = bv->vmesh->seg + 1; /* ensure we don't walk past the segments */
+ if (f->len == 4) {
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, f, NULL);
+ }
+
while (f->len > 4 && split_count > 0) {
BMLoop *l_new;
BLI_assert(l_a->f == f);
@@ -3746,6 +4023,9 @@ static void bevel_build_quadstrip(BevelParams *bp, BMesh *bm, BevVert *bv)
/* walk around the new face to get the next verts to split */
l_a = l_new->prev;
l_b = l_new->next->next;
+
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, f, NULL);
}
split_count--;
}
@@ -3808,6 +4088,13 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv)
flag_out_edge(bm, bme);
}
}
+ else if (bp->faceHash) {
+ BMFace *f;
+ BMIter fiter;
+ BM_ITER_ELEM(f, &fiter, bv->v, BM_FACES_OF_VERT) {
+ BLI_ghash_insert(bp->faceHash, f, NULL);
+ }
+ }
}
/* Given that the boundary is built, now make the actual BMVerts
@@ -4722,13 +5009,15 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
VMesh *vm1, *vm2;
EdgeHalf *e1, *e2;
BMEdge *bme1, *bme2, *center_bme;
- BMFace *f1, *f2, *f;
+ BMFace *f1, *f2, *f, *r_f;
BMVert *verts[4];
BMFace *faces[4];
BMEdge *edges[4];
int k, nseg, i1, i2, odd, mid;
int mat_nr = bp->mat_nr;
+ bool do_fix_shading_bv = bp->faceHash != NULL;
+
if (!BM_edge_is_manifold(bme))
return;
@@ -4784,18 +5073,18 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
/* straddles a seam: choose to interpolate in f1 and snap right edge to bme */
edges[0] = edges[1] = NULL;
edges[2] = edges[3] = bme;
- bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
}
else {
/* straddles but not a seam: interpolate left half in f1, right half in f2 */
- bev_create_ngon(bm, verts, 4, faces, NULL, NULL, mat_nr, true);
+ r_f = bev_create_ngon(bm, verts, 4, faces, NULL, NULL, mat_nr, true);
}
}
else if (!odd && k == mid) {
/* left poly that touches an even center line on right */
edges[0] = edges[1] = NULL;
edges[2] = edges[3] = bme;
- bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
center_bme = BM_edge_exists(verts[2], verts[3]);
BLI_assert(center_bme != NULL);
}
@@ -4803,13 +5092,15 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
/* right poly that touches an even center line on left */
edges[0] = edges[1] = bme;
edges[2] = edges[3] = NULL;
- bev_create_ngon(bm, verts, 4, NULL, f2, edges, mat_nr, true);
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f2, edges, mat_nr, true);
}
else {
/* doesn't cross or touch the center line, so interpolate in appropriate f1 or f2 */
f = (k <= mid) ? f1 : f2;
- bev_create_ngon(bm, verts, 4, NULL, f, NULL, mat_nr, true);
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f, NULL, mat_nr, true);
}
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, r_f, NULL);
verts[0] = verts[3];
verts[1] = verts[2];
}
@@ -5349,7 +5640,8 @@ void BM_mesh_bevel(
const float segments, const float profile,
const bool vertex_only, const bool use_weights, const bool limit_offset,
const struct MDeformVert *dvert, const int vertex_group, const int mat,
- const bool loop_slide)
+ const bool loop_slide, const bool mark_seam, const bool mark_sharp,
+ const int hnmode, void *mod_bmop_customdata)
{
BMIter iter;
BMVert *v, *v_next;
@@ -5358,6 +5650,9 @@ void BM_mesh_bevel(
BevelParams bp = {NULL};
GHashIterator giter;
+ BMOperator *op = NULL;
+ BevelModNorEditData *clnordata;
+
bp.offset = offset;
bp.offset_type = offset_type;
bp.seg = segments;
@@ -5370,8 +5665,12 @@ void BM_mesh_bevel(
bp.dvert = dvert;
bp.vertex_group = vertex_group;
bp.mat_nr = mat;
+ bp.mark_seam = mark_seam;
+ bp.mark_sharp = mark_sharp;
+ bp.hnmode = hnmode;
+ bp.faceHash = NULL;
- if (profile >= 0.999f) { /* r ~ 692, so PRO_SQUARE_R is 1e4 */
+ if (profile >= 0.950f) { /* r ~ 692, so PRO_SQUARE_R is 1e4 */
bp.pro_super_r = PRO_SQUARE_R;
}
@@ -5382,6 +5681,15 @@ void BM_mesh_bevel(
BLI_memarena_use_calloc(bp.mem_arena);
set_profile_spacing(&bp);
+ /* Stores BMOp if executed through tool else stores BevelModNorEditData */
+ if (bm->use_toolflags)
+ op = mod_bmop_customdata;
+ else {
+ clnordata = mod_bmop_customdata;
+ clnordata->faceHash = BLI_ghash_ptr_new(__func__);
+ bp.faceHash = clnordata->faceHash;
+ }
+
/* Analyze input vertices, sorting edges and assigning initial new vertex positions */
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
@@ -5426,6 +5734,15 @@ void BM_mesh_bevel(
}
}
+ /* Extend edge data like sharp edges and precompute normals for harden */
+ GHASH_ITER(giter, bp.vert_hash) {
+ bv = BLI_ghashIterator_getValue(&giter);
+ bevel_extend_edge_data(bv);
+ if (bm->use_toolflags) {
+ bevel_harden_normals_mode(&bp, bv, op);
+ }
+ }
+
/* Rebuild face polygons around affected vertices */
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h
index 386dc8a1fce..f8a77d431cc 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.h
+++ b/source/blender/bmesh/tools/bmesh_bevel.h
@@ -33,6 +33,7 @@ void BM_mesh_bevel(
BMesh *bm, const float offset, const int offset_type, const float segments,
const float profile, const bool vertex_only, const bool use_weights,
const bool limit_offset, const struct MDeformVert *dvert, const int vertex_group,
- const int mat, const bool loop_slide);
+ const int mat, const bool loop_slide, const bool mark_seam, const bool mark_sharp,
+ const int hnmode, void *mod_bmop_customdata);
#endif /* __BMESH_BEVEL_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index b1a8c3ccb86..a35bb81a1c2 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -81,12 +81,6 @@
/* use accelerated overlap check */
#define USE_BVH
-// #define USE_BOOLEAN_RAYCAST_DRAW
-
-#ifdef USE_BOOLEAN_RAYCAST_DRAW
-/* insert bl_debug_draw_quad_clear... here */
-#endif
-
// #define USE_DUMP
static void tri_v3_scale(
@@ -1006,10 +1000,6 @@ bool BM_mesh_intersect(
int i_a, i_b;
#endif
-#ifdef USE_BOOLEAN_RAYCAST_DRAW
- bl_debug_draw_quad_clear();
-#endif
-
s.bm = bm;
s.edgetri_cache = BLI_ghash_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__);
@@ -1607,17 +1597,6 @@ bool BM_mesh_intersect(
do_flip = (side == 0);
break;
}
-
-#ifdef USE_BOOLEAN_RAYCAST_DRAW
- {
- uint colors[4] = {0x00000000, 0xffffffff, 0xff000000, 0x0000ff};
- float co_other[3] = {UNPACK3(co)};
- co_other[0] += 1000.0f;
- bl_debug_color_set(colors[(hits & 1) == 1]);
- bl_debug_draw_edge_add(co, co_other);
- }
-#endif
-
}
if (do_remove) {