From 5d2d36b0686d7253f9d61c00a63d273aba17677a Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Fri, 25 May 2018 22:24:24 +0530 Subject: Applied soc-2017-normal-tools --- release/datafiles/locale | 2 +- release/scripts/addons | 2 +- release/scripts/addons_contrib | 2 +- .../scripts/modules/bpy_extras/keyconfig_utils.py | 1 + release/scripts/startup/bl_operators/mesh.py | 50 - .../startup/bl_ui/properties_data_modifier.py | 16 + release/scripts/startup/bl_ui/space_view3d.py | 24 + .../scripts/startup/bl_ui/space_view3d_toolbar.py | 21 + source/blender/blenkernel/BKE_editmesh.h | 1 + source/blender/blenkernel/BKE_mesh.h | 3 + source/blender/blenkernel/intern/editderivedmesh.c | 2 +- source/blender/blenkernel/intern/editmesh.c | 23 + source/blender/blenkernel/intern/mesh_evaluate.c | 9 +- source/blender/bmesh/bmesh_class.h | 29 + source/blender/bmesh/intern/bmesh_mesh.c | 407 +++++- source/blender/bmesh/intern/bmesh_mesh.h | 20 +- source/blender/bmesh/intern/bmesh_operator_api.h | 1 + source/blender/draw/intern/draw_cache_impl_mesh.c | 4 +- source/blender/editors/include/ED_screen.h | 1 + source/blender/editors/include/ED_transform.h | 2 + source/blender/editors/mesh/editmesh_tools.c | 1375 ++++++++++++++++++++ source/blender/editors/mesh/editmesh_undo.c | 2 + source/blender/editors/mesh/editmesh_utils.c | 5 +- source/blender/editors/mesh/mesh_intern.h | 10 + source/blender/editors/mesh/mesh_ops.c | 12 + source/blender/editors/screen/screen_ops.c | 10 + .../blender/editors/space_outliner/outliner_draw.c | 1 + source/blender/editors/transform/transform.c | 220 +++- source/blender/editors/transform/transform.h | 4 + source/blender/editors/transform/transform_ops.c | 24 + source/blender/makesdna/DNA_modifier_types.h | 27 + source/blender/makesdna/DNA_scene_types.h | 11 + source/blender/makesrna/RNA_access.h | 1 + source/blender/makesrna/intern/rna_modifier.c | 67 + source/blender/makesrna/intern/rna_scene.c | 15 + source/blender/modifiers/CMakeLists.txt | 1 + source/blender/modifiers/MOD_modifiertypes.h | 1 + source/blender/modifiers/intern/MOD_util.c | 1 + .../blender/modifiers/intern/MOD_weighted_normal.c | 670 ++++++++++ source/tools | 2 +- 40 files changed, 2997 insertions(+), 82 deletions(-) create mode 100644 source/blender/modifiers/intern/MOD_weighted_normal.c diff --git a/release/datafiles/locale b/release/datafiles/locale index d3349b42856..59495b4b590 160000 --- a/release/datafiles/locale +++ b/release/datafiles/locale @@ -1 +1 @@ -Subproject commit d3349b42856d00c278f72f2a5909a6c96b9cdb5e +Subproject commit 59495b4b59077aa1cc68fffbdae1463af980f08e diff --git a/release/scripts/addons b/release/scripts/addons index 8f2fd7e23f0..27970761a18 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit 8f2fd7e23f0b5ce023440182f51c40e88d663325 +Subproject commit 27970761a18926abe1b0020aa350305e3109a537 diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib index 34a27a42d78..6a4f93c9b8f 160000 --- a/release/scripts/addons_contrib +++ b/release/scripts/addons_contrib @@ -1 +1 @@ -Subproject commit 34a27a42d781d80f9f1833bad8cc5b2abcac2933 +Subproject commit 6a4f93c9b8f36b19bd02087abf3d7f5983df035a diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py index b0e4d65a3ce..b8fd96e2ec8 100644 --- a/release/scripts/modules/bpy_extras/keyconfig_utils.py +++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py @@ -56,6 +56,7 @@ KM_HIERARCHY = [ ('Particle', 'EMPTY', 'WINDOW', []), ('Knife Tool Modal Map', 'EMPTY', 'WINDOW', []), + ('Custom Normals Modal Map', 'EMPTY', 'WINDOW', []), ('Paint Stroke Modal', 'EMPTY', 'WINDOW', []), ('Paint Curve', 'EMPTY', 'WINDOW', []), diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py index c7a11c23c3f..8543847122d 100644 --- a/release/scripts/startup/bl_operators/mesh.py +++ b/release/scripts/startup/bl_operators/mesh.py @@ -203,57 +203,7 @@ class MeshSelectPrev(Operator): return {'FINISHED'} -# XXX This is hackish (going forth and back from Object mode...), to be redone once we have proper support of -# custom normals in BMesh/edit mode. -class MehsSetNormalsFromFaces(Operator): - """Set the custom vertex normals from the selected faces ones""" - bl_idname = "mesh.set_normals_from_faces" - bl_label = "Set Normals From Faces" - bl_options = {'REGISTER', 'UNDO'} - - @classmethod - def poll(cls, context): - return (context.mode == 'EDIT_MESH' and context.edit_object.data.polygons) - - def execute(self, context): - import mathutils - - bpy.ops.object.mode_set(mode='OBJECT') - obj = context.active_object - me = obj.data - - v2nors = {} - for p in me.polygons: - if not p.select: - continue - for lidx, vidx in zip(p.loop_indices, p.vertices): - assert(me.loops[lidx].vertex_index == vidx) - v2nors.setdefault(vidx, []).append(p.normal) - - for nors in v2nors.values(): - nors[:] = [sum(nors, mathutils.Vector((0, 0, 0))).normalized()] - - if not me.has_custom_normals: - me.create_normals_split() - me.calc_normals_split() - - normals = [] - for l in me.loops: - nor = v2nors.get(l.vertex_index, [None])[0] - if nor is None: - nor = l.normal - normals.append(nor.to_tuple()) - - me.normals_split_custom_set(normals) - - me.free_normals_split() - bpy.ops.object.mode_set(mode='EDIT') - - return {'FINISHED'} - - classes = ( - MehsSetNormalsFromFaces, MeshMirrorUV, MeshSelectNext, MeshSelectPrev, diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 28e39959c7e..fb1d62a92db 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -1557,6 +1557,22 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): if md.rest_source == 'BIND': layout.operator("object.correctivesmooth_bind", text="Unbind" if is_bind else "Bind") + def WEIGHTED_NORMAL(self, layout, ob, md): + layout.label("Weighting Mode:") + split = layout.split(align=True) + col = split.column(align=True) + col.prop(md, "mode", text="") + col.prop(md, "weight", text="Weight") + col.prop(md, "keep_sharp") + + col = split.column(align=True) + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.active = bool(md.vertex_group) + row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT') + col.prop(md, "thresh", text="Threshold") + col.prop(md, "face_influence") + classes = ( DATA_PT_modifiers, diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 324a4259e38..4f5791101a9 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2777,6 +2777,30 @@ class VIEW3D_MT_edit_mesh_normals(Menu): layout.operator("mesh.flip_normals") layout.operator("mesh.set_normals_from_faces", text="Set From Faces") + layout.operator("transform.rotate_normal", text="Rotate Normal") + layout.operator("mesh.point_normals", text="Point normals to target") + + layout.operator("mesh.merge_normals", text="Merge") + layout.operator("mesh.split_normals", text="Split") + + layout.operator("mesh.average_normals", text="Average Normals") + + layout.label(text="Normal Vector") + + layout.operator("mesh.normals_tools", text="Copy").mode = 'COPY' + layout.operator("mesh.normals_tools", text="Paste").mode = 'PASTE' + + layout.operator("mesh.normals_tools", text="Multiply").mode = 'MULTIPLY' + layout.operator("mesh.normals_tools", text="Add").mode = 'ADD' + + layout.operator("mesh.normals_tools", text="Reset").mode = 'RESET' + + layout.operator("mesh.smoothen_normals", text="Smoothen") + + layout.label(text="Face Strength") + layout.operator("mesh.mod_weighted_strength", text="Face select", icon = "FACESEL").set = False + layout.operator("mesh.mod_weighted_strength", text="Set Strength", icon = "ZOOMIN").set = True + class VIEW3D_MT_edit_mesh_shading(Menu): bl_label = "Shading" diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 004ea8b0e52..9a1bff86ed3 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1297,6 +1297,26 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, Panel): sub.prop(pe, "fade_frames", slider=True) +class VIEW3D_PT_tools_normal(View3DPanel, Panel): + bl_category = "" + bl_context = ".mesh_edit" + bl_label = "Normal Tools" + + def draw(self, context): + layout = self.layout + toolsettings = context.tool_settings + + col = layout.column(align=True) + col.label(text="Normal Vector") + col.prop(toolsettings, "normal_vector", text="") + + layout.separator() + layout.label(text="Face Strength") + layout.prop(toolsettings, "face_strength", text="") + + col = layout.column(align=True) + + # Grease Pencil drawing tools class VIEW3D_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel): bl_space_type = 'VIEW_3D' @@ -1361,6 +1381,7 @@ classes = ( VIEW3D_PT_tools_grease_pencil_sculpt, VIEW3D_PT_tools_grease_pencil_brush, VIEW3D_PT_tools_grease_pencil_brushcurves, + VIEW3D_PT_tools_normal, ) if __name__ == "__main__": # only for live edit. diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h index 5e456fea64f..39986129c61 100644 --- a/source/blender/blenkernel/BKE_editmesh.h +++ b/source/blender/blenkernel/BKE_editmesh.h @@ -93,6 +93,7 @@ void BKE_editmesh_free(BMEditMesh *em); void BKE_editmesh_color_free(BMEditMesh *em); void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype); float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]; +void BKE_editmesh_lnorspace_update(BMEditMesh *em); /* editderivedmesh.c */ /* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index f1326974f10..6e0514fd009 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -269,6 +269,8 @@ typedef struct MLoopNorSpace { * - BMLoop pointers. */ struct LinkNode *loops; char flags; + + void *user_data; /* To be used for extended processing related to loop normal spaces (aka smooth fans). */ } MLoopNorSpace; /** * MLoopNorSpace.flags @@ -284,6 +286,7 @@ typedef struct MLoopNorSpaceArray { MLoopNorSpace **lspacearr; /* MLoop aligned array */ struct LinkNode *loops_pool; /* Allocated once, avoids to call BLI_linklist_prepend_arena() for each loop! */ char data_type; /* Whether we store loop indices, or pointers to BMLoop. */ + int num_spaces; /* Number of clnors spaces defined in this array. */ struct MemArena *mem; } MLoopNorSpaceArray; /** diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index f5e5a37c7d7..657461e3bf5 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -202,7 +202,7 @@ static void emDM_calcLoopNormalsSpaceArray( cd_loop_clnors_offset = clnors_data ? -1 : CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); BM_loops_calc_normal_vcos(bm, vertexCos, vertexNos, polyNos, use_split_normals, split_angle, loopNos, - r_lnors_spacearr, clnors_data, cd_loop_clnors_offset); + r_lnors_spacearr, clnors_data, cd_loop_clnors_offset, false); #ifdef DEBUG_CLNORS if (r_lnors_spacearr) { int i; diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index b63ab276b14..a7f93ca6c49 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -246,3 +246,26 @@ float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3] return orco; } + +void BKE_editmesh_lnorspace_update(BMEditMesh *em) +{ + BMesh *bm = em->bm; + + /* We need to create clnors data is none exist yet, otherwise there is no way to edit them. */ + /* Similar code to MESH_OT_customdata_custom_splitnormals_add operator, we want to keep same shading + * in case we were using autosmooth so far... */ + /* Note: there is a problem here, which is that is someone starts a normal editing operation on previously + * autosmooth-ed mesh, and cancel that operation, generated clnors data remain, with related sharp edges + * (and hence autosmooth is 'lost'). + * Not sure how critical this is, and how to fix that issue? */ + if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) { + Mesh *me = em->ob->data; + if (me->flag & ME_AUTOSMOOTH) { + BM_edges_sharp_from_angle_set(bm, me->smoothresh); + + me->drawflag |= ME_DRAWSHARP; + } + } + + BM_lnorspace_update(bm); +} diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 068be0ef304..997201fc4d0 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -465,6 +465,8 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoo mem = lnors_spacearr->mem; lnors_spacearr->lspacearr = BLI_memarena_calloc(mem, sizeof(MLoopNorSpace *) * (size_t)numLoops); lnors_spacearr->loops_pool = BLI_memarena_alloc(mem, sizeof(LinkNode) * (size_t)numLoops); + + lnors_spacearr->num_spaces = 0; } BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX)); lnors_spacearr->data_type = data_type; @@ -472,21 +474,24 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoo void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr) { - BLI_memarena_clear(lnors_spacearr->mem); + lnors_spacearr->num_spaces = 0; lnors_spacearr->lspacearr = NULL; lnors_spacearr->loops_pool = NULL; + BLI_memarena_clear(lnors_spacearr->mem); } void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr) { - BLI_memarena_free(lnors_spacearr->mem); + lnors_spacearr->num_spaces = 0; lnors_spacearr->lspacearr = NULL; lnors_spacearr->loops_pool = NULL; + BLI_memarena_free(lnors_spacearr->mem); lnors_spacearr->mem = NULL; } MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr) { + lnors_spacearr->num_spaces++; return BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace)); } diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index bec2c7a1f45..8159aae1ab8 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; /* Stores MLoopNorSpaceArray for this BMesh */ + 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_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index 8071637d95e..79c835cca11 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,10 @@ 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. */ +/* XXX Should we rather add a new internal flag? */ +#define BM_LNORSPACE_UPDATE _FLAG_MF + typedef struct BMEdgesCalcVectorsData { /* Read-only data. */ const float (*vcos)[3]; @@ -638,7 +648,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 +705,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 +910,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 +1028,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 +1039,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,6 +1062,380 @@ 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); } +void BM_lnorspacearr_store(BMesh *bm, float(*r_lnors)[3]) +{ + BLI_assert(bm->lnor_spacearr != NULL); + + if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) { + BM_data_layer_add(bm, &bm->ldata, CD_CUSTOMLOOPNORMAL); + } + + int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + + 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); +} + +/* will change later */ +#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); + } +} + +/** +* 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)++; + } + } + } + } + } +} + +/* 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; +} + +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); +} + +int BM_total_loop_select(BMesh *bm) +{ + int r_sel = 0; + BMVert *v; + BMIter viter; + + 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; +} + static void UNUSED_FUNCTION(bm_mdisps_space_set)( Object *ob, BMesh *bm, int from, int to) { @@ -1142,6 +1537,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); } @@ -1158,6 +1554,9 @@ 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_ex(BMesh *bm, const char htype, int elem_offset[4]) diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h index b4443c748ce..44887e81157 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,24 @@ 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); +#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); 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/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 00d404e1571..e8add4890d8 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -423,7 +423,7 @@ static MeshRenderData *mesh_render_data_create_ex( int totloop = bm->totloop; if (is_auto_smooth) { rdata->loop_normals = MEM_mallocN(sizeof(*rdata->loop_normals) * totloop, __func__); - BM_loops_calc_normal_vcos(bm, NULL, NULL, NULL, true, split_angle, rdata->loop_normals, NULL, NULL, -1); + BM_loops_calc_normal_vcos(bm, NULL, NULL, NULL, true, split_angle, rdata->loop_normals, NULL, NULL, -1, false); } rdata->loop_len = totloop; bm_ensure_types |= BM_LOOP; @@ -720,7 +720,7 @@ static MeshRenderData *mesh_render_data_create_ex( /* Should we store the previous array of `loop_normals` in somewhere? */ rdata->loop_len = bm->totloop; rdata->loop_normals = MEM_mallocN(sizeof(*rdata->loop_normals) * rdata->loop_len, __func__); - BM_loops_calc_normal_vcos(bm, NULL, NULL, NULL, true, split_angle, rdata->loop_normals, NULL, NULL, -1); + BM_loops_calc_normal_vcos(bm, NULL, NULL, NULL, true, split_angle, rdata->loop_normals, NULL, NULL, -1, false); } bool calc_active_tangent = false; diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 749d1347eb3..a91d373ac46 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -277,6 +277,7 @@ int ED_operator_object_active_editable_font(struct bContext *C); int ED_operator_editmesh(struct bContext *C); int ED_operator_editmesh_view3d(struct bContext *C); int ED_operator_editmesh_region_view3d(struct bContext *C); +int ED_operator_editmesh_auto_smooth(struct bContext *C); int ED_operator_editarmature(struct bContext *C); int ED_operator_editcurve(struct bContext *C); int ED_operator_editcurve_3d(struct bContext *C); diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index e17d02abcd7..36f87e1b494 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -89,6 +89,7 @@ enum TfmMode { TFM_VERT_SLIDE, TFM_SEQ_SLIDE, TFM_BONE_ENVELOPE_DIST, + TFM_NORMAL_ROTATION, }; /* TRANSFORM CONTEXTS */ @@ -152,6 +153,7 @@ int BIF_countTransformOrientation(const struct bContext *C); #define P_NO_TEXSPACE (1 << 11) #define P_CENTER (1 << 12) #define P_GPENCIL_EDIT (1 << 13) +#define P_CLNOR_INVALIDATE (1 << 14) void Transform_Properties(struct wmOperatorType *ot, int flags); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 8438375a97f..77c90a6591b 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -41,11 +41,16 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BLI_bitmap.h" +#include "BLI_heap.h" #include "BLI_listbase.h" +#include "BLI_linklist.h" +#include "BLI_linklist_stack.h" #include "BLI_noise.h" #include "BLI_math.h" #include "BLI_rand.h" #include "BLI_sort_utils.h" +#include "BLI_string.h" #include "BKE_layer.h" #include "BKE_material.h" @@ -54,6 +59,7 @@ #include "BKE_report.h" #include "BKE_texture.h" #include "BKE_main.h" +#include "BKE_mesh.h" #include "BKE_editmesh.h" #include "DEG_depsgraph.h" @@ -6916,3 +6922,1372 @@ void MESH_OT_mark_freestyle_face(wmOperatorType *ot) /** \} */ #endif /* WITH_FREESTYLE */ + +/********************** Loop normals editing tools modal map. **********************/ + +/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ +/* NOTE: We could add more here, like e.g. a switch between local or global coordinates of target, + * use numinput to type in explicit vector values... */ +enum { + /* Generic commands. */ + EDBM_CLNOR_MODAL_CANCEL = 1, + EDBM_CLNOR_MODAL_CONFIRM = 2, + + /* Point To operator. */ + EDBM_CLNOR_MODAL_POINTTO_RESET = 101, + EDBM_CLNOR_MODAL_POINTTO_INVERT = 102, + EDBM_CLNOR_MODAL_POINTTO_SPHERIZE = 103, + EDBM_CLNOR_MODAL_POINTTO_ALIGN = 104, + + EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE = 110, + EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT = 111, + EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT = 112, + EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR = 113, + EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED = 114, +}; + +/* called in transform_ops.c, on each regeneration of keymaps */ +wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {EDBM_CLNOR_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, + {EDBM_CLNOR_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + /* Point To operator. */ + {EDBM_CLNOR_MODAL_POINTTO_RESET, "RESET", 0, "Reset", "Reset normals to initial ones"}, + {EDBM_CLNOR_MODAL_POINTTO_INVERT, "INVERT", 0, "Invert", "Toggle inversion of affected normals"}, + {EDBM_CLNOR_MODAL_POINTTO_SPHERIZE, "SPHERIZE", 0, "Spherize", "Interpolate between new and original normals"}, + {EDBM_CLNOR_MODAL_POINTTO_ALIGN, "ALIGN", 0, "Align", "Make all affected normals parallel"}, + + {EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE, "USE_MOUSE", 0, "Use Mouse", "Follow mouse cursor position"}, + {EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT, "USE_PIVOT", 0, "Use Pivot", + "Use current rotation/scaling pivot point coordinates"}, + {EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT, "USE_OBJECT", 0, "Use Object", "Use current edited object's location"}, + {EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR, "SET_USE_3DCURSOR", 0, "Set and Use 3D Cursor", + "Set new 3D cursor position and use it"}, + {EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED, "SET_USE_SELECTED", 0, "Select and Use Mesh Item", + "Select new active mesh element and use its location"}, + {0, NULL, 0, NULL, NULL} + }; + static const char *keymap_name = "Custom Normals Modal Map"; + + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, keymap_name); + + /* We only need to add map once */ + if (keymap && keymap->modal_items) + return NULL; + + keymap = WM_modalkeymap_add(keyconf, keymap_name, modal_items); + + /* Generic items for modal map. */ + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EDBM_CLNOR_MODAL_CANCEL); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_CANCEL); + + WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, EDBM_CLNOR_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, EDBM_CLNOR_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_CONFIRM); + + /* Point To items for modal map */ + WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_RESET); + WM_modalkeymap_add_item(keymap, IKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_INVERT); + WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_SPHERIZE); + WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_ALIGN); + + WM_modalkeymap_add_item(keymap, MKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE); + WM_modalkeymap_add_item(keymap, LKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT); + WM_modalkeymap_add_item(keymap, OKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT); + + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_CLICK, KM_CTRL, 0, EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_CLICK, KM_CTRL, 0, EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED); + + WM_modalkeymap_assign(keymap, "MESH_OT_point_normals"); + + return keymap; +} + +#define CLNORS_VALID_VEC_LEN (1e-4f) + +/********************** 'Point to' Loop Normals **********************/ + +enum { + EDBM_CLNOR_POINTTO_MODE_COORDINATES = 1, + EDBM_CLNOR_POINTTO_MODE_MOUSE = 2, +}; + +static EnumPropertyItem clnors_pointto_mode_items[] = { + {EDBM_CLNOR_POINTTO_MODE_COORDINATES, "COORDINATES", 0, "Coordinates", + "Use static coordinates (defined by various means)"}, + {EDBM_CLNOR_POINTTO_MODE_MOUSE, "MOUSE", 0, "Mouse", "Follow mouse cursor"}, + {0, NULL, 0, NULL, NULL} +}; + +/* Initialize loop normal data */ +static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + BKE_editmesh_lnorspace_update(em); + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); + + op->customdata = lnors_ed_arr; + + return lnors_ed_arr->totloop; +} + +static void point_normals_free(bContext *C, wmOperator *op) +{ + BMLoopNorEditDataArray *lnors_ed_arr = op->customdata; + BM_loop_normal_editdata_array_free(lnors_ed_arr); + op->customdata = NULL; + ED_area_headerprint(CTX_wm_area(C), NULL); +} + +static void point_normals_update_header(bContext *C, wmOperator *op) +{ + char header[UI_MAX_DRAW_STR]; + char buf[UI_MAX_DRAW_STR]; + + char *p = buf; + int available_len = sizeof(buf); + +#define WM_MODALKEY(_id) \ + WM_modalkeymap_operator_items_to_string_buf(op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p) + + BLI_snprintf(header, sizeof(header), IFACE_("%s: confirm, %s: cancel, " + "%s: point to mouse (%s), %s: point to Pivot, " + "%s: point to object origin, %s: reset normals, " + "%s: set & point to 3D cursor, %s: select & point to mesh item, " + "%s: invert normals (%s), %s: spherize (%s), %s: align (%s)"), + WM_MODALKEY(EDBM_CLNOR_MODAL_CONFIRM), WM_MODALKEY(EDBM_CLNOR_MODAL_CANCEL), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE), + WM_bool_as_string(RNA_enum_get(op->ptr, "mode") == EDBM_CLNOR_POINTTO_MODE_MOUSE), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_RESET), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_INVERT), WM_bool_as_string(RNA_boolean_get(op->ptr, "invert")), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SPHERIZE), WM_bool_as_string(RNA_boolean_get(op->ptr, "spherize")), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_ALIGN), WM_bool_as_string(RNA_boolean_get(op->ptr, "align"))); + +#undef WM_MODALKEY + + ED_area_headerprint(CTX_wm_area(C), header); +} + +/* TODO move that to generic function in BMesh? */ +static void bmesh_selected_verts_center_calc(BMesh *bm, float *r_center) +{ + BMVert *v; + BMIter viter; + int i = 0; + + zero_v3(r_center); + BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + add_v3_v3(r_center, v->co); + i++; + } + } + mul_v3_fl(r_center, 1.0f / (float)i); +} + +static void point_normals_apply(bContext *C, wmOperator *op, float target[3], const bool do_reset) +{ + Object *obedit = CTX_data_edit_object(C); + BMesh *bm = BKE_editmesh_from_object(obedit)->bm; + BMLoopNorEditDataArray *lnors_ed_arr = op->customdata; + + const bool do_invert = RNA_boolean_get(op->ptr, "invert"); + const bool do_spherize = RNA_boolean_get(op->ptr, "spherize"); + const bool do_align = RNA_boolean_get(op->ptr, "align"); + float center[3]; + + if (do_align && !do_reset) { + bmesh_selected_verts_center_calc(bm, center); + } + + sub_v3_v3(target, obedit->loc); /* Move target to local coordinates. */ + + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (do_reset) { + copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); + } + else if (do_spherize) { + /* Note that this is *not* real spherical interpolation. Probably good enough in this case though? */ + const float strength = RNA_float_get(op->ptr, "spherize_strength"); + float spherized_normal[3]; + + sub_v3_v3v3(spherized_normal, target, lnor_ed->loc); + normalize_v3(spherized_normal); /* otherwise, multiplication by strength is meaningless... */ + mul_v3_fl(spherized_normal, strength); + mul_v3_v3fl(lnor_ed->nloc, lnor_ed->niloc, 1.0f - strength); + add_v3_v3(lnor_ed->nloc, spherized_normal); + } + else if (do_align) { + sub_v3_v3v3(lnor_ed->nloc, target, center); + } + else { + sub_v3_v3v3(lnor_ed->nloc, target, lnor_ed->loc); + } + + if (do_invert && !do_reset) { + negate_v3(lnor_ed->nloc); + } + if (normalize_v3(lnor_ed->nloc) >= CLNORS_VALID_VEC_LEN) { + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); + } + } +} + +static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + View3D *v3d = CTX_wm_view3d(C); + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + float target[3]; + + int ret = OPERATOR_PASS_THROUGH; + int mode = RNA_enum_get(op->ptr, "mode"); + int new_mode = mode; + bool force_mousemove = false; + bool do_reset = false; + + PropertyRNA *prop_target = RNA_struct_find_property(op->ptr, "target_location"); + + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EDBM_CLNOR_MODAL_CONFIRM: + RNA_property_float_get_array(op->ptr, prop_target, target); + ret = OPERATOR_FINISHED; + break; + + case EDBM_CLNOR_MODAL_CANCEL: + do_reset = true; + ret = OPERATOR_CANCELLED; + break; + + case EDBM_CLNOR_MODAL_POINTTO_RESET: + do_reset = true; + ret = OPERATOR_RUNNING_MODAL; + break; + + case EDBM_CLNOR_MODAL_POINTTO_INVERT: + { + PropertyRNA *prop_invert = RNA_struct_find_property(op->ptr, "invert"); + RNA_property_boolean_set(op->ptr, prop_invert, !RNA_property_boolean_get(op->ptr, prop_invert)); + RNA_property_float_get_array(op->ptr, prop_target, target); + ret = OPERATOR_RUNNING_MODAL; + break; + } + + case EDBM_CLNOR_MODAL_POINTTO_SPHERIZE: + { + PropertyRNA *prop_spherize = RNA_struct_find_property(op->ptr, "spherize"); + RNA_property_boolean_set(op->ptr, prop_spherize, !RNA_property_boolean_get(op->ptr, prop_spherize)); + RNA_property_float_get_array(op->ptr, prop_target, target); + ret = OPERATOR_RUNNING_MODAL; + break; + } + + case EDBM_CLNOR_MODAL_POINTTO_ALIGN: + { + PropertyRNA *prop_align = RNA_struct_find_property(op->ptr, "align"); + RNA_property_boolean_set(op->ptr, prop_align, !RNA_property_boolean_get(op->ptr, prop_align)); + RNA_property_float_get_array(op->ptr, prop_target, target); + ret = OPERATOR_RUNNING_MODAL; + break; + } + + case EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE: + new_mode = EDBM_CLNOR_POINTTO_MODE_MOUSE; + force_mousemove = true; /* We want to immediately update to mouse cursor position... */ + ret = OPERATOR_RUNNING_MODAL; + break; + + case EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT: + new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; + copy_v3_v3(target, obedit->loc); + ret = OPERATOR_RUNNING_MODAL; + break; + + case EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR: + new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; + ED_view3d_cursor3d_update(C, event->mval); + copy_v3_v3(target, ED_view3d_cursor3d_get(scene, v3d)->location); + break; + + case EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED: + new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; + view3d_operator_needs_opengl(C); + if (EDBM_select_pick(C, event->mval, false, false, false)) { + ED_object_editmode_calc_active_center(obedit, false, target); /* Point to newly selected active. */ + add_v3_v3(target, obedit->loc); + ret = OPERATOR_RUNNING_MODAL; + } + break; + + case EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT: + new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; + switch (scene->toolsettings->transform_pivot_point) { + case V3D_AROUND_CENTER_BOUNDS: /* calculateCenterBound */ + { + BMVert *v; + BMIter viter; + float min[3], max[3]; + int i = 0; + + BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + if (i) { + minmax_v3v3_v3(min, max, v->co); + } + else { + copy_v3_v3(min, v->co); + copy_v3_v3(max, v->co); + } + i++; + } + } + mid_v3_v3v3(target, min, max); + add_v3_v3(target, obedit->loc); + break; + } + + case V3D_AROUND_CENTER_MEAN: + { + bmesh_selected_verts_center_calc(bm, target); + add_v3_v3(target, obedit->loc); + break; + } + + case V3D_AROUND_CURSOR: + copy_v3_v3(target, ED_view3d_cursor3d_get(scene, v3d)->location); + break; + + case V3D_AROUND_ACTIVE: + if (!ED_object_editmode_calc_active_center(obedit, false, target)) { + zero_v3(target); + } + add_v3_v3(target, obedit->loc); + break; + + default: + BKE_report(op->reports, RPT_WARNING, "Does not support Individual Origin as pivot"); + copy_v3_v3(target, obedit->loc); + } + ret = OPERATOR_RUNNING_MODAL; + break; + default: + break; + } + } + + if (new_mode != mode) { + mode = new_mode; + RNA_enum_set(op->ptr, "mode", mode); + } + + /* Only handle mousemove event in case we are in mouse mode. */ + if (event->type == MOUSEMOVE || force_mousemove) { + if (mode == EDBM_CLNOR_POINTTO_MODE_MOUSE) { + ARegion *ar = CTX_wm_region(C); + float center[3]; + + bmesh_selected_verts_center_calc(bm, center); + + ED_view3d_win_to_3d_int(v3d, ar, center, event->mval, target); + + ret = OPERATOR_RUNNING_MODAL; + } + } + + if (ret != OPERATOR_PASS_THROUGH) { + if (!ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) { + RNA_property_float_set_array(op->ptr, prop_target, target); + } + point_normals_apply(C, op, target, do_reset); + EDBM_update_generic(em, true, false); /* Recheck bools. */ + + point_normals_update_header(C, op); + } + + if (ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) { + point_normals_free(C, op); + } + + return ret; +} + +static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (!point_normals_init(C, op, event)) { + point_normals_free(C, op); + return OPERATOR_CANCELLED; + } + + WM_event_add_modal_handler(C, op); + + point_normals_update_header(C, op); + + op->flag |= OP_IS_MODAL_GRAB_CURSOR; + return OPERATOR_RUNNING_MODAL; +} + +static int edbm_point_normals_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (!point_normals_init(C, op, NULL)) { + point_normals_free(C, op); + return OPERATOR_CANCELLED; + } + + /* Note that 'mode' is ignored in exec case, we directly use vector stored in target_location, whatever that is. */ + + float target[3]; + RNA_float_get_array(op->ptr, "target_location", target); + + point_normals_apply(C, op, target, false); + + EDBM_update_generic(em, true, false); + point_normals_free(C, op); + + return OPERATOR_FINISHED; +} + +static bool point_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +{ + const char *prop_id = RNA_property_identifier(prop); + + /* Only show strength option if spherize is enabled. */ + if (STREQ(prop_id, "spherize_strength")) { + return (bool)RNA_boolean_get(ptr, "spherize"); + } + + /* Else, show it! */ + return true; +} + +static void edbm_point_normals_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + /* Main auto-draw call */ + uiDefAutoButsRNA(layout, &ptr, point_normals_draw_check_prop, '\0', false); +} + +void MESH_OT_point_normals(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Point Normals to Target"; + ot->description = "Point selected custom normals to specified Target"; + ot->idname = "MESH_OT_point_normals"; + + /* api callbacks */ + ot->exec = edbm_point_normals_exec; + ot->invoke = edbm_point_normals_invoke; + ot->modal = edbm_point_normals_modal; + ot->poll = ED_operator_editmesh_auto_smooth; + ot->ui = edbm_point_normals_ui; + ot->cancel = point_normals_free; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "mode", clnors_pointto_mode_items, EDBM_CLNOR_POINTTO_MODE_COORDINATES, + "Mode", "How to define coordinates to point custom normals to"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN); + + RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert affected normals"); + + RNA_def_boolean(ot->srna, "align", false, "Align", "Make all affected normals parallel"); + + RNA_def_float_vector(ot->srna, "target_location", 3, (float[3]){0.0f, 0.0f, 0.0f}, -FLT_MAX, FLT_MAX, + "Target", "Target location to which normals will point", -1000.0f, 1000.0f); + + RNA_def_boolean(ot->srna, "spherize", false, + "Spherize", "Interpolate between original and new normals"); + + RNA_def_float(ot->srna, "spherize_strength", 0.1, 0.0f, 1.0f, + "Spherize Strength", "Ratio of spherized normal to original normal", 0.0f, 1.0f); +} + +/********************** Split/Merge Loop Normals **********************/ + +static void normals_splitmerge_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; + } + + 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); +} + +static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr) +{ + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + + BLI_SMALLSTACK_DECLARE(clnors, short *); + + BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); + + normals_splitmerge_loops_edges_tag(bm, false); + + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (BM_elem_flag_test(lnor_ed->loop, BM_ELEM_TAG)) { + continue; + } + + MLoopNorSpace *lnor_space = bm->lnor_spacearr->lspacearr[lnor_ed->loop_index]; + + if ((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0) { + LinkNode *loops = lnor_space->loops; + float avg_normal[3] = {0.0f, 0.0f, 0.0f}; + short *clnors_data; + + for (; loops; loops = loops->next) { + BMLoop *l = loops->link; + const int loop_index = BM_elem_index_get(l); + + BMLoopNorEditData *lnor_ed_tmp = lnors_ed_arr->lidx_to_lnor_editdata[loop_index]; + BLI_assert(lnor_ed_tmp->loop_index == loop_index && lnor_ed_tmp->loop == l); + add_v3_v3(avg_normal, lnor_ed_tmp->nloc); + BLI_SMALLSTACK_PUSH(clnors, lnor_ed_tmp->clnors_data); + BM_elem_flag_enable(l, BM_ELEM_TAG); + } + if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { + /* If avg normal is nearly 0, set clnor to default value. */ + zero_v3(avg_normal); + } + while ((clnors_data = BLI_SMALLSTACK_POP(clnors))) { + BKE_lnor_space_custom_normal_to_data(lnor_space, avg_normal, clnors_data); + } + } + } +} + +static void normals_split(BMesh *bm) +{ + BMFace *f; + BMLoop *l, *l_curr, *l_first; + BMIter fiter; + + BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); + + normals_splitmerge_loops_edges_tag(bm, true); + + const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + l_curr = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) && (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) || + (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_curr)))) + { + if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) { + const int loop_index = BM_elem_index_get(l_curr); + short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors); + } + else { + BMVert *v_pivot = l_curr->v; + BMEdge *e_next; + const BMEdge *e_org = l_curr->e; + BMLoop *lfan_pivot, *lfan_pivot_next; + + lfan_pivot = l_curr; + e_next = lfan_pivot->e; + BLI_SMALLSTACK_DECLARE(loops, BMLoop *); + float avg_normal[3] = { 0.0f }; + + while (true) { + lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); + if (lfan_pivot_next) { + BLI_assert(lfan_pivot_next->v == v_pivot); + } + else { + e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e; + } + + BLI_SMALLSTACK_PUSH(loops, lfan_pivot); + add_v3_v3(avg_normal, lfan_pivot->f->no); + + if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { + break; + } + lfan_pivot = lfan_pivot_next; + } + if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { + /* If avg normal is nearly 0, set clnor to default value. */ + zero_v3(avg_normal); + } + while ((l = BLI_SMALLSTACK_POP(loops))) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors); + } + } + } + } while ((l_curr = l_curr->next) != l_first); + } +} + +static int normals_split_merge(bContext *C, const bool do_merge) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMEdge *e; + BMIter eiter; + + BKE_editmesh_lnorspace_update(em); + + BMLoopNorEditDataArray *lnors_ed_arr = do_merge ? BM_loop_normal_editdata_array_init(bm) : NULL; + + mesh_set_smooth_faces(em, do_merge); + + BM_ITER_MESH(e, &eiter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + BM_elem_flag_set(e, BM_ELEM_SMOOTH, do_merge); + } + } + if (do_merge == 0) { + Mesh *me = obedit->data; + me->drawflag |= ME_DRAWSHARP; + } + + bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; + BKE_editmesh_lnorspace_update(em); + + if (do_merge) { + normals_merge(bm, lnors_ed_arr); + } + else { + normals_split(bm); + } + + if (lnors_ed_arr) { + BM_loop_normal_editdata_array_free(lnors_ed_arr); + } + + EDBM_update_generic(em, true, false); + + return OPERATOR_FINISHED; +} + +static int edbm_merge_normals_exec(bContext *C, wmOperator *UNUSED(op)) +{ + return normals_split_merge(C, true); +} + +void MESH_OT_merge_normals(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Merge Normals"; + ot->description = "Merge custom normals of selected vertices"; + ot->idname = "MESH_OT_merge_normals"; + + /* api callbacks */ + ot->exec = edbm_merge_normals_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int edbm_split_normals_exec(bContext *C, wmOperator *UNUSED(op)) +{ + return normals_split_merge(C, false); +} + +void MESH_OT_split_normals(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Split Normals"; + ot->description = "Split custom normals of selected vertices"; + ot->idname = "MESH_OT_split_normals"; + + /* api callbacks */ + ot->exec = edbm_split_normals_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************** Average Loop Normals **********************/ + +enum { + EDBM_CLNOR_AVERAGE_LOOP = 1, + EDBM_CLNOR_AVERAGE_FACE_AREA = 2, + EDBM_CLNOR_AVERAGE_ANGLE = 3, +}; + +static EnumPropertyItem average_method_items[] = { + {EDBM_CLNOR_AVERAGE_LOOP, "CUSTOM_NORMAL", 0, "Custom Normal", "Take Average of vert Normals"}, + {EDBM_CLNOR_AVERAGE_FACE_AREA, "FACE_AREA", 0, "Face Area", "Set all vert normals by Face Area"}, + {EDBM_CLNOR_AVERAGE_ANGLE, "CORNER_ANGLE", 0, "Corner Angle", "Set all vert normals by Corner Angle"}, + {0, NULL, 0, NULL, NULL} +}; + +static int edbm_average_normals_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMLoop *l, *l_curr, *l_first; + BMIter fiter; + + bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; + BKE_editmesh_lnorspace_update(em); + + const int average_type = RNA_enum_get(op->ptr, "average_type"); + const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + const float absweight = (float) RNA_int_get(op->ptr, "weight"); + const float threshold = RNA_float_get(op->ptr, "threshold"); + + float weight = absweight / 50.0f; + if (absweight == 100.0f) { + weight = (float)SHRT_MAX; + } + else if (absweight == 1.0f) { + weight = 1 / (float)SHRT_MAX; + } + else if ((weight - 1) * 25 > 1) { + weight = (weight - 1) * 25; + } + + normals_splitmerge_loops_edges_tag(bm, true); + + Heap *loop_weight = BLI_heap_new(); + + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + l_curr = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) && (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) || + (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_curr)))) + { + if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) { + const int loop_index = BM_elem_index_get(l_curr); + short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors); + } + else { + BMVert *v_pivot = l_curr->v; + BMEdge *e_next; + const BMEdge *e_org = l_curr->e; + BMLoop *lfan_pivot, *lfan_pivot_next; + + lfan_pivot = l_curr; + e_next = lfan_pivot->e; + + while (true) { + lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); + if (lfan_pivot_next) { + BLI_assert(lfan_pivot_next->v == v_pivot); + } + else { + e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e; + } + + float val = 1.0f; + if (average_type == EDBM_CLNOR_AVERAGE_FACE_AREA) { + val = 1.0f / BM_face_calc_area(lfan_pivot->f); + } + else if (average_type == EDBM_CLNOR_AVERAGE_ANGLE) { + val = 1.0f / BM_loop_calc_face_angle(lfan_pivot); + } + + BLI_heap_insert(loop_weight, val, lfan_pivot); + + if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { + break; + } + lfan_pivot = lfan_pivot_next; + } + + BLI_SMALLSTACK_DECLARE(loops, BMLoop *); + float wnor[3], avg_normal[3] = { 0.0f }, count = 0; + float val = BLI_heap_node_value(BLI_heap_top(loop_weight)); + + while (!BLI_heap_is_empty(loop_weight)) { + const float cur_val = BLI_heap_node_value(BLI_heap_top(loop_weight)); + if (!compare_ff(val, cur_val, threshold)) { + count++; + val = cur_val; + } + l = BLI_heap_pop_min(loop_weight); + BLI_SMALLSTACK_PUSH(loops, l); + + const float n_weight = pow(weight, count); + + if (average_type == EDBM_CLNOR_AVERAGE_LOOP) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_data_to_normal(bm->lnor_spacearr->lspacearr[l_index], clnors, wnor); + } + else { + copy_v3_v3(wnor, l->f->no); + } + mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight)); + add_v3_v3(avg_normal, wnor); + } + + if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { + /* If avg normal is nearly 0, set clnor to default value. */ + zero_v3(avg_normal); + } + while ((l = BLI_SMALLSTACK_POP(loops))) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors); + } + } + } + } while ((l_curr = l_curr->next) != l_first); + } + + BLI_heap_free(loop_weight, NULL); + EDBM_update_generic(em, true, false); + + return OPERATOR_FINISHED; +} + +static bool average_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +{ + const char *prop_id = RNA_property_identifier(prop); + const int average_type = RNA_enum_get(ptr, "average_type"); + + /* Only show weight/threshold options in loop average type. */ + if (STREQ(prop_id, "weight")) { + return (average_type == EDBM_CLNOR_AVERAGE_LOOP); + } + else if (STREQ(prop_id, "threshold")) { + return (average_type == EDBM_CLNOR_AVERAGE_LOOP); + } + + /* Else, show it! */ + return true; +} + +static void edbm_average_normals_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + /* Main auto-draw call */ + uiDefAutoButsRNA(layout, &ptr, average_normals_draw_check_prop, '\0', false); +} + +void MESH_OT_average_normals(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Average Normals"; + ot->description = "Average custom normals of selected vertices"; + ot->idname = "MESH_OT_average_normals"; + + /* api callbacks */ + ot->exec = edbm_average_normals_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + ot->ui = edbm_average_normals_ui; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "average_type", average_method_items, EDBM_CLNOR_AVERAGE_LOOP, + "Type", "Averaging method"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN); + + RNA_def_int(ot->srna, "weight", 50, 1, 100, "Weight", "Weight applied per face", 1, 100); + + RNA_def_float(ot->srna, "threshold", 0.01f, 0, 10, "Threshold", + "Threshold value for different weights to be considered equal", 0, 5); +} + +/********************** Custom Normal Interface Tools **********************/ + +enum { + EDBM_CLNOR_TOOLS_COPY = 1, + EDBM_CLNOR_TOOLS_PASTE = 2, + EDBM_CLNOR_TOOLS_MULTIPLY = 3, + EDBM_CLNOR_TOOLS_ADD = 4, + EDBM_CLNOR_TOOLS_RESET = 5, +}; + +static EnumPropertyItem normal_vector_tool_items[] = { + {EDBM_CLNOR_TOOLS_COPY, "COPY", 0, "Copy Normal", "Copy normal to buffer"}, + {EDBM_CLNOR_TOOLS_PASTE, "PASTE", 0, "Paste Normal", "Paste normal from buffer"}, + {EDBM_CLNOR_TOOLS_ADD, "ADD", 0, "Add Normal", "Add normal vector with selection"}, + {EDBM_CLNOR_TOOLS_MULTIPLY, "MULTIPLY", 0, "Multiply Normal", "Multiply normal vector with selection"}, + {EDBM_CLNOR_TOOLS_RESET, "RESET", 0, "Reset Normal", "Reset buffer and/or normal of selected element"}, + {0, NULL, 0, NULL, NULL} +}; + +static int edbm_normals_tools_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + const int mode = RNA_enum_get(op->ptr, "mode"); + const bool absolute = RNA_boolean_get(op->ptr, "absolute"); + + BKE_editmesh_lnorspace_update(em); + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + + float *normal_vector = scene->toolsettings->normal_vector; + + switch (mode) { + case EDBM_CLNOR_TOOLS_COPY: + if (bm->totfacesel != 1 && lnors_ed_arr->totloop != 1 && bm->totvertsel != 1) { + BKE_report(op->reports, RPT_ERROR, "Can only copy custom normal, vertex normal or face normal"); + BM_loop_normal_editdata_array_free(lnors_ed_arr); + return OPERATOR_CANCELLED; + } + bool join = true; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (!compare_v3v3(lnors_ed_arr->lnor_editdata->nloc, lnor_ed->nloc, 1e-4f)) { + join = false; + } + } + if (lnors_ed_arr->totloop == 1) { + copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc); + } + else if (bm->totfacesel == 1) { + BMFace *f; + BMIter fiter; + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + copy_v3_v3(scene->toolsettings->normal_vector, f->no); + } + } + } + else if (join) { + copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc); + } + break; + + case EDBM_CLNOR_TOOLS_PASTE: + if (!absolute) { + if (normalize_v3(normal_vector) < CLNORS_VALID_VEC_LEN) { + /* If normal is nearly 0, do nothing. */ + break; + } + } + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (absolute) { + float abs_normal[3]; + copy_v3_v3(abs_normal, lnor_ed->loc); + negate_v3(abs_normal); + add_v3_v3(abs_normal, normal_vector); + + if (normalize_v3(abs_normal) < CLNORS_VALID_VEC_LEN) { + /* If abs normal is nearly 0, set clnor to initial value. */ + copy_v3_v3(abs_normal, lnor_ed->niloc); + } + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], abs_normal, lnor_ed->clnors_data); + } + else { + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], normal_vector, lnor_ed->clnors_data); + } + } + break; + + case EDBM_CLNOR_TOOLS_MULTIPLY: + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + mul_v3_v3(lnor_ed->nloc, normal_vector); + + if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) { + /* If abs normal is nearly 0, set clnor to initial value. */ + copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); + } + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); + } + break; + + case EDBM_CLNOR_TOOLS_ADD: + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + add_v3_v3(lnor_ed->nloc, normal_vector); + + if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) { + /* If abs normal is nearly 0, set clnor to initial value. */ + copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); + } + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); + } + break; + + case EDBM_CLNOR_TOOLS_RESET: + zero_v3(normal_vector); + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], normal_vector, lnor_ed->clnors_data); + } + break; + + default: + BLI_assert(0); + break; + } + + BM_loop_normal_editdata_array_free(lnors_ed_arr); + + EDBM_update_generic(em, true, false); + return OPERATOR_FINISHED; +} + +static bool normals_tools_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +{ + const char *prop_id = RNA_property_identifier(prop); + const int mode = RNA_enum_get(ptr, "mode"); + + /* Only show absolute option in paste mode. */ + if (STREQ(prop_id, "absolute")) { + return (mode == EDBM_CLNOR_TOOLS_PASTE); + } + + /* Else, show it! */ + return true; +} + +static void edbm_normals_tools_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + /* Main auto-draw call */ + uiDefAutoButsRNA(layout, &ptr, normals_tools_draw_check_prop, '\0', false); +} + +void MESH_OT_normals_tools(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Normals Vector Tools"; + ot->description = "Custom normals tools using Normal Vector of UI"; + ot->idname = "MESH_OT_normals_tools"; + + /* api callbacks */ + ot->exec = edbm_normals_tools_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + ot->ui = edbm_normals_tools_ui; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "mode", normal_vector_tool_items, EDBM_CLNOR_TOOLS_COPY, + "Mode", "Mode of tools taking input from Interface"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN); + + RNA_def_boolean(ot->srna, "absolute", false, "Absolute Coordinates", "Copy Absolute coordinates or Normal vector"); +} + +static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMVert *v; + BMEdge *e; + BMLoop *l; + BMIter fiter, viter, eiter, liter; + + const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp"); + + BKE_editmesh_lnorspace_update(em); + + float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * bm->totvert, __func__); + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_ITER_ELEM(v, &viter, f, BM_VERTS_OF_FACE) { + const int v_index = BM_elem_index_get(v); + add_v3_v3(vnors[v_index], f->no); + } + } + } + for (int i = 0; i < bm->totvert; i++) { + if (!is_zero_v3(vnors[i]) && normalize_v3(vnors[i]) < CLNORS_VALID_VEC_LEN) { + zero_v3(vnors[i]); + } + } + + BLI_bitmap *loop_set = BLI_BITMAP_NEW(bm->totloop, __func__); + const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM(e, &eiter, f, BM_EDGES_OF_FACE) { + if (!keep_sharp || (BM_elem_flag_test(e, BM_ELEM_SMOOTH) && BM_elem_flag_test(e, BM_ELEM_SELECT))) { + BM_ITER_ELEM(v, &viter, e, BM_VERTS_OF_EDGE) { + l = BM_face_vert_share_loop(f, v); + const int l_index = BM_elem_index_get(l); + const int v_index = BM_elem_index_get(l->v); + + if (!is_zero_v3(vnors[v_index])) { + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[l_index], vnors[v_index], clnors); + + if (bm->lnor_spacearr->lspacearr[l_index]->flags & MLNOR_SPACE_IS_SINGLE) { + BLI_BITMAP_ENABLE(loop_set, l_index); + } + else { + LinkNode *loops = bm->lnor_spacearr->lspacearr[l_index]->loops; + for (; loops; loops = loops->next) { + BLI_BITMAP_ENABLE(loop_set, BM_elem_index_get((BMLoop *)loops->link)); + } + } + } + } + } + } + } + + int v_index; + BM_ITER_MESH_INDEX(v, &viter, bm, BM_VERTS_OF_MESH, v_index) { + BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) { + if (BLI_BITMAP_TEST(loop_set, BM_elem_index_get(l))) { + const int loop_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], vnors[v_index], clnors); + } + } + } + + MEM_freeN(loop_set); + MEM_freeN(vnors); + EDBM_update_generic(em, true, false); + } + + return OPERATOR_FINISHED; +} + +void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Normals From Faces"; + ot->description = "Set the custom normals from the selected faces ones"; + ot->idname = "MESH_OT_set_normals_from_faces"; + + /* api callbacks */ + ot->exec = edbm_set_normals_from_faces_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "keep_sharp", 0, "Keep Sharp Edges", "Do not set sharp edges to face"); +} + +static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMLoop *l; + BMIter fiter, liter; + + BKE_editmesh_lnorspace_update(em); + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); + + float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop, __func__); + + /* This is weird choice of operation, taking all loops of faces of current vertex... Could lead to some rather + * far away loops weighting as much as very close ones (topologically speaking), with complex polygons. + * Using topological distance here (rather than geometrical one) makes sense imho, but would rather go with + * a more consistent and flexible code, we could even add max topological distance to take into account, + * and a weighting curve... + * Would do that later though, think for now we can live with that choice. --mont29 */ + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + l = lnor_ed->loop; + float loop_normal[3]; + + BM_ITER_ELEM(f, &fiter, l->v, BM_FACES_OF_VERT) { + BMLoop *l_other; + BM_ITER_ELEM(l_other, &liter, f, BM_LOOPS_OF_FACE) { + const int l_index_other = BM_elem_index_get(l_other); + short *clnors = BM_ELEM_CD_GET_VOID_P(l_other, lnors_ed_arr->cd_custom_normal_offset); + BKE_lnor_space_custom_data_to_normal(bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal); + add_v3_v3(smooth_normal[i], loop_normal); + } + } + } + + const float factor = RNA_float_get(op->ptr, "factor"); + + lnor_ed = lnors_ed_arr->lnor_editdata; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + float current_normal[3]; + + if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) { + /* Skip in case smoothen normal is invalid... */ + continue; + } + + BKE_lnor_space_custom_data_to_normal( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->clnors_data, current_normal); + + /* Note: again, this is not true spherical interpolation that normals would need... + * But it's probably good enough for now. */ + mul_v3_fl(current_normal, 1.0f - factor); + mul_v3_fl(smooth_normal[i], factor); + add_v3_v3(current_normal, smooth_normal[i]); + + if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) { + /* Skip in case smoothen normal is invalid... */ + continue; + } + + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], current_normal, lnor_ed->clnors_data); + } + + BM_loop_normal_editdata_array_free(lnors_ed_arr); + MEM_freeN(smooth_normal); + + EDBM_update_generic(em, true, false); + + return OPERATOR_FINISHED; +} + +void MESH_OT_smoothen_normals(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Smoothen Normals"; + ot->description = "Smoothen custom normals based on adjacent vertex normals"; + ot->idname = "MESH_OT_smoothen_normals"; + + /* api callbacks */ + ot->exec = edbm_smoothen_normals_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0f, "Factor", + "Specifies weight of smooth vs original normal", 0.0f, 1.0f); +} + +/********************** Weighted Normal Modifier Face Strength **********************/ + +static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMIter fiter; + + BM_select_history_clear(bm); + + const char *layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID; + int cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id); + if (cd_prop_int_index == -1) { + BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, layer_id); + cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id); + } + cd_prop_int_index -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT); + const int cd_prop_int_offset = CustomData_get_n_offset(&bm->pdata, CD_PROP_INT, cd_prop_int_index); + + const int face_strength = scene->toolsettings->face_strength; + const bool set = RNA_boolean_get(op->ptr, "set"); + BM_mesh_elem_index_ensure(bm, BM_FACE); + + if (set) { + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset); + *strength = face_strength; + } + } + } + else { + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset); + if (*strength == face_strength) { + BM_face_select_set(bm, f, true); + BM_select_history_store(bm, f); + } + else { + BM_face_select_set(bm, f, false); + } + } + } + + EDBM_update_generic(em, false, false); + return OPERATOR_FINISHED; +} + +void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Face Strength"; + ot->description = "Set/Get strength of face (used in Weighted Normal modifier)"; + ot->idname = "MESH_OT_mod_weighted_strength"; + + /* api callbacks */ + ot->exec = edbm_mod_weighted_strength_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_boolean(ot->srna, "set", 0, "Set value", "Set Value of faces"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN); +} \ No newline at end of file diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 4d4b7a098b0..6fb7a713ce0 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -598,6 +598,8 @@ static void undomesh_to_editmesh(UndoMesh *um, BMEditMesh *em, Mesh *obmesh) bm->selectmode = um->selectmode; em->ob = ob; + bm->spacearr_dirty = BM_SPACEARR_DIRTY_ALL; + /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens * if the active is a basis for any other. */ if (key && (key->type == KEY_RELATIVE)) { diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index ab44e017fc6..16c1a2c45ec 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1343,7 +1343,10 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d /* in debug mode double check we didn't need to recalculate */ BLI_assert(BM_mesh_elem_table_check(em->bm) == true); } - + if (em->bm->spacearr_dirty & BM_SPACEARR_BMO_SET) { + BM_lnorspace_invalidate(em->bm, false); + em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET; + } /* don't keep stale derivedMesh data around, see: [#38872] */ BKE_editmesh_free_derivedmesh(em); diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index b9e9ae9c1fd..e585f407052 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -240,6 +240,16 @@ void MESH_OT_duplicate(struct wmOperatorType *ot); void MESH_OT_merge(struct wmOperatorType *ot); void MESH_OT_remove_doubles(struct wmOperatorType *ot); void MESH_OT_poke(struct wmOperatorType *ot); +void MESH_OT_point_normals(struct wmOperatorType *ot); +void MESH_OT_merge_normals(struct wmOperatorType *ot); +void MESH_OT_split_normals(struct wmOperatorType *ot); +void MESH_OT_normals_tools(struct wmOperatorType *ot); +void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot); +void MESH_OT_average_normals(struct wmOperatorType *ot); +void MESH_OT_smoothen_normals(struct wmOperatorType *ot); +void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot); + +struct wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf); #ifdef WITH_FREESTYLE void MESH_OT_mark_freestyle_edge(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 9f3ef6f958d..60200313b8c 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -200,6 +200,15 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_bisect); WM_operatortype_append(MESH_OT_symmetrize); WM_operatortype_append(MESH_OT_symmetry_snap); + + WM_operatortype_append(MESH_OT_point_normals); + WM_operatortype_append(MESH_OT_merge_normals); + WM_operatortype_append(MESH_OT_split_normals); + WM_operatortype_append(MESH_OT_normals_tools); + WM_operatortype_append(MESH_OT_set_normals_from_faces); + WM_operatortype_append(MESH_OT_average_normals); + WM_operatortype_append(MESH_OT_smoothen_normals); + WM_operatortype_append(MESH_OT_mod_weighted_strength); } #if 0 /* UNUSED, remove? */ @@ -446,6 +455,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MESH_OT_split", YKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "MESH_OT_vert_connect_path", JKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "MESH_OT_point_normals", LKEY, KM_PRESS, KM_ALT, 0); + /* Vertex Slide */ WM_keymap_add_item(keymap, "TRANSFORM_OT_vert_slide", VKEY, KM_PRESS, KM_SHIFT, 0); /* use KM_CLICK because same key is used for tweaks */ @@ -489,5 +500,6 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) ED_keymap_proportional_editmode(keyconf, keymap, true); knifetool_modal_keymap(keyconf); + point_normals_modal_keymap(keyconf); } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 2063191658b..6392af2a5e0 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -47,6 +47,7 @@ #include "DNA_gpencil_types.h" #include "DNA_scene_types.h" #include "DNA_meta_types.h" +#include "DNA_mesh_types.h" #include "DNA_mask_types.h" #include "DNA_node_types.h" #include "DNA_workspace_types.h" @@ -351,6 +352,15 @@ int ED_operator_editmesh_region_view3d(bContext *C) return 0; } +int ED_operator_editmesh_auto_smooth(bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + if (obedit && obedit->type == OB_MESH && (((Mesh *)(obedit->data))->flag & ME_AUTOSMOOTH)) { + return NULL != BKE_editmesh_from_object(obedit); + } + return 0; +} + int ED_operator_editarmature(bContext *C) { Object *obedit = CTX_data_edit_object(C); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 7d200c904cd..883078bc83c 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1006,6 +1006,7 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto ICON_DRAW(ICON_MOD_DATA_TRANSFER); break; case eModifierType_NormalEdit: + case eModifierType_WeightedNormal: ICON_DRAW(ICON_MOD_NORMALEDIT); break; /* Default */ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index e20ef264a93..569cd4efafc 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -41,6 +41,7 @@ #include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_mask_types.h" +#include "DNA_mesh_types.h" #include "DNA_movieclip_types.h" #include "DNA_scene_types.h" /* PET modes */ #include "DNA_workspace_types.h" @@ -64,6 +65,7 @@ #include "BKE_unit.h" #include "BKE_scene.h" #include "BKE_mask.h" +#include "BKE_mesh.h" #include "BKE_report.h" #include "BKE_workspace.h" @@ -94,6 +96,7 @@ #include "UI_resources.h" #include "RNA_access.h" +#include "RNA_define.h" #include "BLF_api.h" #include "BLT_translation.h" @@ -114,6 +117,7 @@ static void postInputRotation(TransInfo *t, float values[3]); static void ElementRotation(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around); static void initSnapSpatial(TransInfo *t, float r_snap[3]); +static void storeCustomLNorValue(TransDataContainer *t, BMesh *bm); /* Transform Callbacks */ static void initBend(TransInfo *t); @@ -139,6 +143,9 @@ static void applyToSphere(TransInfo *t, const int mval[2]); static void initRotation(TransInfo *t); static void applyRotation(TransInfo *t, const int mval[2]); +static void initNormalRotation(TransInfo *t); +static void applyNormalRotation(TransInfo *t, const int mval[2]); + static void initShrinkFatten(TransInfo *t); static void applyShrinkFatten(TransInfo *t, const int mval[2]); @@ -1481,6 +1488,18 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; } break; + case NKEY: + if (ELEM(t->mode, TFM_ROTATION)) { + if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) { + restoreTransObjects(t); + resetTransModal(t); + resetTransRestrictions(t); + initNormalRotation(t); + t->redraw = TREDRAW_HARD; + handled = true; + } + } + break; default: break; } @@ -2430,6 +2449,9 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve case TFM_SEQ_SLIDE: initSeqSlide(t); break; + case TFM_NORMAL_ROTATION: + initNormalRotation(t); + break; } if (t->state == TRANS_CANCEL) { @@ -2437,6 +2459,39 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve return 0; } + if ((prop = RNA_struct_find_property(op->ptr, "preserve_clnor"))) { + if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) { + + FOREACH_TRANS_DATA_CONTAINER(t, tc) { + if ((((Mesh *)(tc->obedit->data))->flag & ME_AUTOSMOOTH)) { + BMEditMesh *em = NULL;// BKE_editmesh_from_object(t->obedit); + bool do_skip = false; + + /* Currently only used for two of three most frequent transform ops, can include more ops. + * Note that scaling cannot be included here, non-uniform scaling will affect normals. */ + if (ELEM(t->mode, TFM_TRANSLATION, TFM_ROTATION)) { + if (em->bm->totvertsel == em->bm->totvert) { + /* No need to invalidate if whole mesh is selected. */ + do_skip = true; + } + } + + if (t->flag & T_MODAL) { + RNA_property_boolean_set(op->ptr, prop, false); + } + else if (!do_skip) { + const bool preserve_clnor = RNA_property_boolean_get(op->ptr, prop); + if (preserve_clnor) { + BKE_editmesh_lnorspace_update(em); + t->flag |= T_CLNOR_REBUILD; + } + BM_lnorspace_invalidate(em->bm, true); + } + } + } + } + } + t->context = NULL; return 1; @@ -2497,6 +2552,12 @@ int transformEnd(bContext *C, TransInfo *t) restoreTransObjects(t); // calls recalcData() } else { + if (t->flag & T_CLNOR_REBUILD) { + FOREACH_TRANS_DATA_CONTAINER(t, tc) { + BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); + BM_lnorspace_rebuild(em->bm, true); + } + } exit_code = OPERATOR_FINISHED; } @@ -3815,6 +3876,28 @@ static void initRotation(TransInfo *t) copy_v3_v3(t->axis_orig, t->axis); } +/* Used by Transform Rotation and Transform Normal Rotation */ +static void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final) +{ + size_t ofs = 0; + + if (hasNumInput(&t->num)) { + char c[NUM_STR_REP_LEN]; + + outputNumInput(&(t->num), c, &t->scene->unit); + + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext); + } + else { + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Rot: %.2f%s %s"), + RAD2DEGF(final), t->con.text, t->proptext); + } + + if (t->flag & T_PROP_EDIT_ALL) { + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); + } +} + /** * Applies values of rotation to `td->loc` and `td->ext->quat` * based on a rotation matrix (mat) and a pivot (center). @@ -4101,21 +4184,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) t->values[0] = final; - if (hasNumInput(&t->num)) { - char c[NUM_STR_REP_LEN]; - - outputNumInput(&(t->num), c, &t->scene->unit); - - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext); - } - else { - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %.2f%s %s"), - RAD2DEGF(final), t->con.text, t->proptext); - } - - if (t->flag & T_PROP_EDIT_ALL) { - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); - } + headerRotation(t, str, final); applyRotationValue(t, final, t->axis); @@ -4243,6 +4312,127 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) /** \} */ +/* -------------------------------------------------------------------- */ +/* Transform (Normal Rotation) */ + +/** \name Transform Normal Rotation +* \{ */ + +static void storeCustomLNorValue(TransDataContainer *tc, BMesh *bm) +{ + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + + tc->custom.mode.data = lnors_ed_arr; + tc->custom.mode.free_cb = freeCustomNormalArray; +} + +void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data) +{ + BMLoopNorEditDataArray *lnors_ed_arr = custom_data->data; + + if (t->state == TRANS_CANCEL) { + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); + BMesh *bm = em->bm; + + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { /* Restore custom loop normal on cancel */ + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->niloc, lnor_ed->clnors_data); + } + } + + BM_loop_normal_editdata_array_free(lnors_ed_arr); + + tc->custom.mode.data = NULL; + tc->custom.mode.free_cb = NULL; +} + +static void initNormalRotation(TransInfo *t) +{ + t->mode = TFM_NORMAL_ROTATION; + t->transform = applyNormalRotation; + + setInputPostFct(&t->mouse, postInputRotation); + initMouseInputMode(t, &t->mouse, INPUT_ANGLE); + + t->idx_max = 0; + t->num.idx_max = 0; + t->snap[0] = 0.0f; + t->snap[1] = DEG2RAD(5.0); + t->snap[2] = DEG2RAD(1.0); + + copy_v3_fl(t->num.val_inc, t->snap[2]); + t->num.unit_sys = t->scene->unit.system; + t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS); + t->num.unit_type[0] = B_UNIT_ROTATION; + + FOREACH_TRANS_DATA_CONTAINER(t, tc) { + BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); + BMesh *bm = em->bm; + + BKE_editmesh_lnorspace_update(em); + + storeCustomLNorValue(tc, bm); + } + + negate_v3_v3(t->axis, t->viewinv[2]); + normalize_v3(t->axis); + + copy_v3_v3(t->axis_orig, t->axis); +} + +/* Works by getting custom normal from clnor_data, transform, then store */ +static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2])) +{ + char str[UI_MAX_DRAW_STR]; + + if ((t->con.mode & CON_APPLY) && t->con.applyRot) { + t->con.applyRot(t, NULL, NULL, t->axis, NULL); + } + else { + /* reset axis if constraint is not set */ + copy_v3_v3(t->axis, t->axis_orig); + } + + FOREACH_TRANS_DATA_CONTAINER(t, tc) { + BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); + BMesh *bm = em->bm; + + BMLoopNorEditDataArray *lnors_ed_arr = tc->custom.mode.data; + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + + float axis[3]; + float mat[3][3]; + float angle = t->values[0]; + copy_v3_v3(axis, t->axis); + + snapGridIncrement(t, &angle); + + applySnapping(t, &angle); + + applyNumInput(&t->num, &angle); + + headerRotation(t, str, angle); + + axis_angle_normalized_to_mat3(mat, axis, angle); + + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + mul_v3_m3v3(lnor_ed->nloc, mat, lnor_ed->niloc); + + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); + } + } + + recalcData(t); + + ED_area_headerprint(t->sa, str); +} + +/** \} */ + + /* -------------------------------------------------------------------- */ /* Transform (Translation) */ diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 2cf66794709..136512516e8 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -601,6 +601,8 @@ typedef struct TransInfo { /** #TransInfo.center has been set, don't change it. */ #define T_OVERRIDE_CENTER (1 << 25) +#define T_CLNOR_REBUILD (1 << 26) + /* TransInfo->modifiers */ #define MOD_CONSTRAINT_SELECT 0x01 #define MOD_PRECISION 0x02 @@ -869,6 +871,8 @@ bool applyTransformOrientation(const struct TransformOrientation *ts, float r_ma int getTransformOrientation_ex(const struct bContext *C, float normal[3], float plane[3], const short around); int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3]); +void freeCustomNormalArray(TransInfo *t, TransCustomData *custom_data); + void freeEdgeSlideTempFaces(EdgeSlideData *sld); void freeEdgeSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data); void projectEdgeSlideData(TransInfo *t, bool is_final); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 36c444a0ca3..4fbb50d678e 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -81,6 +81,7 @@ static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide"; static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease"; static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight"; static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide"; +static const char OP_NORMAL_ROTATION[] = "TRANSFORM_OT_rotate_normal"; static void TRANSFORM_OT_translate(struct wmOperatorType *ot); static void TRANSFORM_OT_rotate(struct wmOperatorType *ot); @@ -99,6 +100,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot); static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot); static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot); static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot); +static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot); static TransformModeItem transform_modes[] = { @@ -119,6 +121,7 @@ static TransformModeItem transform_modes[] = {OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease}, {OP_EDGE_BWEIGHT, TFM_BWEIGHT, TRANSFORM_OT_edge_bevelweight}, {OP_SEQ_SLIDE, TFM_SEQ_SLIDE, TRANSFORM_OT_seq_slide}, + {OP_NORMAL_ROTATION, TFM_NORMAL_ROTATION, TRANSFORM_OT_rotate_normal}, {NULL, 0} }; @@ -1020,6 +1023,27 @@ static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot) Transform_Properties(ot, P_SNAP); } +static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Normal Rotate"; + ot->description = "Rotate split normal of selected items"; + ot->idname = OP_NORMAL_ROTATION; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + + /* api callbacks */ + ot->invoke = transform_invoke; + ot->exec = transform_exec; + ot->modal = transform_modal; + ot->cancel = transform_cancel; + ot->poll = ED_operator_editmesh_auto_smooth; + + RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); + + Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_MIRROR); +} + + static void TRANSFORM_OT_transform(struct wmOperatorType *ot) { PropertyRNA *prop; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 7faf1cfe193..989e0768fc1 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -89,6 +89,7 @@ typedef enum ModifierType { eModifierType_CorrectiveSmooth = 51, eModifierType_MeshSequenceCache = 52, eModifierType_SurfaceDeform = 53, + eModifierType_WeightedNormal = 54, NUM_MODIFIER_TYPES } ModifierType; @@ -1638,6 +1639,32 @@ enum { MOD_SDEF_MODE_CENTROID = 2, }; +typedef struct WeightedNormalModifierData { + ModifierData modifier; + + char defgrp_name[64]; /* MAX_VGROUP_NAME */ + char mode, flag; + short weight; + float thresh; +} WeightedNormalModifierData; + +/* Name/id of the generic PROP_INT cdlayer storing face weights. */ +#define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID "__mod_weightednormals_faceweight" + +/* WeightedNormalModifierData.mode */ +enum { + MOD_WEIGHTEDNORMAL_MODE_FACE = 0, + MOD_WEIGHTEDNORMAL_MODE_ANGLE = 1, + MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE = 2, +}; + +/* WeightedNormalModifierData.flag */ +enum { + MOD_WEIGHTEDNORMAL_KEEP_SHARP = (1 << 0), + MOD_WEIGHTEDNORMAL_INVERT_VGROUP = (1 << 1), + MOD_WEIGHTEDNORMAL_FACE_INFLUENCE = (1 << 2), +}; + #define MOD_MESHSEQ_READ_ALL \ (MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR) diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 96876e0d0bc..2c39576d0c9 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1309,6 +1309,10 @@ typedef struct ToolSettings { struct CurvePaintSettings curve_paint_settings; struct MeshStatVis statvis; + + /* Normal Editing */ + float normal_vector[3]; + int face_strength; } ToolSettings; /* *************************************************************** */ @@ -1837,6 +1841,13 @@ enum { OB_DRAW_GROUPUSER_ALL = 2 }; +/* toolsettings->face_strength */ +enum { + FACE_STRENGTH_WEAK = -16384, + FACE_STRENGTH_MEDIUM = 0, + FACE_STRENGTH_STRONG = 16384, +}; + /* object_vgroup.c */ /* ToolSettings.vgroupsubset */ typedef enum eVGroupSelect { diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 4744b2e33df..8e0264e208d 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -691,6 +691,7 @@ extern StructRNA RNA_WaveModifier; extern StructRNA RNA_VertexWeightEditModifier; extern StructRNA RNA_VertexWeightMixModifier; extern StructRNA RNA_VertexWeightProximityModifier; +extern StructRNA RNA_WeightedNormalModifier; extern StructRNA RNA_View3DOverlay; extern StructRNA RNA_View3DShading; extern StructRNA RNA_ViewLayer; diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index b1716f6a176..c665442a82f 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -68,6 +68,7 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = { {eModifierType_MeshCache, "MESH_CACHE", ICON_MOD_MESHDEFORM, "Mesh Cache", ""}, {eModifierType_MeshSequenceCache, "MESH_SEQUENCE_CACHE", ICON_MOD_MESHDEFORM, "Mesh Sequence Cache", ""}, {eModifierType_NormalEdit, "NORMAL_EDIT", ICON_MOD_NORMALEDIT, "Normal Edit", ""}, + {eModifierType_WeightedNormal, "WEIGHTED_NORMAL", ICON_MOD_NORMALEDIT, "Weighted Normal", ""}, {eModifierType_UVProject, "UV_PROJECT", ICON_MOD_UVPROJECT, "UV Project", ""}, {eModifierType_UVWarp, "UV_WARP", ICON_MOD_UVPROJECT, "UV Warp", ""}, {eModifierType_WeightVGEdit, "VERTEX_WEIGHT_EDIT", ICON_MOD_VERTEX_WEIGHT, "Vertex Weight Edit", ""}, @@ -413,6 +414,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr) return &RNA_MeshSequenceCacheModifier; case eModifierType_SurfaceDeform: return &RNA_SurfaceDeformModifier; + case eModifierType_WeightedNormal: + return &RNA_WeightedNormalModifier; /* Default */ case eModifierType_None: case eModifierType_ShapeKey: @@ -503,6 +506,7 @@ RNA_MOD_VGROUP_NAME_SET(WeightVGMix, defgrp_name_b); RNA_MOD_VGROUP_NAME_SET(WeightVGMix, mask_defgrp_name); RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, defgrp_name); RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, mask_defgrp_name); +RNA_MOD_VGROUP_NAME_SET(WeightedNormal, defgrp_name); RNA_MOD_VGROUP_NAME_SET(Wireframe, defgrp_name); static void rna_ExplodeModifier_vgroup_get(PointerRNA *ptr, char *value) @@ -4892,6 +4896,68 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); } +static void rna_def_modifier_weightednormal(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem prop_weighting_mode_items[] = { + {MOD_WEIGHTEDNORMAL_MODE_FACE, "FACE_AREA", 0, "Face Area", "Generate face area weighted normals"}, + {MOD_WEIGHTEDNORMAL_MODE_ANGLE, "CORNER_ANGLE", 0, "Corner Angle", "Generate corner angle weighted normals"}, + {MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE, "FACE_AREA_WITH_ANGLE", 0, "Face Area And Angle", + "Generated normals weighted by both face area and angle"}, + {0, NULL, 0, NULL, NULL} + }; + + srna = RNA_def_struct(brna, "WeightedNormalModifier", "Modifier"); + RNA_def_struct_ui_text(srna, "WeightedNormal Modifier", ""); + RNA_def_struct_sdna(srna, "WeightedNormalModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_NORMALEDIT); + + prop = RNA_def_property(srna, "weight", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 1, 100); + RNA_def_property_ui_range(prop, 1, 100, 1, -1); + RNA_def_property_ui_text(prop, "Weight", + "Corrective factor applied to faces' weights, 50 is neutral, " + "lower values increase weight of weak faces, " + "higher values increase weight of strong faces"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, prop_weighting_mode_items); + RNA_def_property_ui_text(prop, "Weighting Mode", "Weighted vertex normal mode to use"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "thresh", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0, 10); + RNA_def_property_ui_range(prop, 0, 10, 1, 2); + RNA_def_property_ui_text(prop, "Threshold", "Threshold value for different weights to be considered equal"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "keep_sharp", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WEIGHTEDNORMAL_KEEP_SHARP); + RNA_def_property_ui_text(prop, "Keep Sharp", + "Keep sharp edges as computed for default split normals, " + "instead of setting a single weighted normal for each vertex."); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "defgrp_name"); + RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modifying the selected areas"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeightedNormalModifier_defgrp_name_set"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WEIGHTEDNORMAL_INVERT_VGROUP); + RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "face_influence", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WEIGHTEDNORMAL_FACE_INFLUENCE); + RNA_def_property_ui_text(prop, "Face Influence", "Use influence of face for weighting"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); +} + void RNA_def_modifier(BlenderRNA *brna) { StructRNA *srna; @@ -5012,6 +5078,7 @@ void RNA_def_modifier(BlenderRNA *brna) rna_def_modifier_normaledit(brna); rna_def_modifier_meshseqcache(brna); rna_def_modifier_surfacedeform(brna); + rna_def_modifier_weightednormal(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 8ac3b8c0a5c..27f9932ebde 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2416,6 +2416,13 @@ static void rna_def_tool_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem mod_weighted_strength[] = { + {FACE_STRENGTH_WEAK, "Weak", 0, "Weak", ""}, + {FACE_STRENGTH_MEDIUM, "Medium", 0, "Medium", ""}, + {FACE_STRENGTH_STRONG, "Strong", 0, "Strong", ""}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem draw_groupuser_items[] = { {OB_DRAW_GROUPUSER_NONE, "NONE", 0, "None", ""}, {OB_DRAW_GROUPUSER_ACTIVE, "ACTIVE", 0, "Active", "Show vertices with no weights in the active group"}, @@ -2816,6 +2823,14 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "edge_mode_live_unwrap", 1); RNA_def_property_ui_text(prop, "Live Unwrap", "Changing edges seam re-calculates UV unwrap"); + prop = RNA_def_property(srna, "normal_vector", PROP_FLOAT, PROP_XYZ); + RNA_def_property_ui_text(prop, "Normal Vector", "Normal Vector used to copy, add or multiply"); + RNA_def_property_ui_range(prop, -10000.0, 10000.0, 1, 3); + + prop = RNA_def_property(srna, "face_strength", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, mod_weighted_strength); + RNA_def_property_ui_text(prop, "Face Strength", "Set strength of face to specified value"); + /* Unified Paint Settings */ prop = RNA_def_property(srna, "unified_paint_settings", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index 397a3263e22..0a619ecf9c7 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -100,6 +100,7 @@ set(SRC intern/MOD_uvproject.c intern/MOD_warp.c intern/MOD_wave.c + intern/MOD_weighted_normal.c intern/MOD_weightvg_util.c intern/MOD_weightvgedit.c intern/MOD_weightvgmix.c diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h index bf121af2bd1..3511b0edbec 100644 --- a/source/blender/modifiers/MOD_modifiertypes.h +++ b/source/blender/modifiers/MOD_modifiertypes.h @@ -86,6 +86,7 @@ extern ModifierTypeInfo modifierType_NormalEdit; extern ModifierTypeInfo modifierType_CorrectiveSmooth; extern ModifierTypeInfo modifierType_MeshSequenceCache; extern ModifierTypeInfo modifierType_SurfaceDeform; +extern ModifierTypeInfo modifierType_WeightedNormal; /* MOD_util.c */ void modifier_type_init(ModifierTypeInfo *types[]); diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index 4a62d17fa27..5d740ae9e20 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -444,5 +444,6 @@ void modifier_type_init(ModifierTypeInfo *types[]) INIT_TYPE(CorrectiveSmooth); INIT_TYPE(MeshSequenceCache); INIT_TYPE(SurfaceDeform); + INIT_TYPE(WeightedNormal); #undef INIT_TYPE } diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c new file mode 100644 index 00000000000..b43ef698cc4 --- /dev/null +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -0,0 +1,670 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_weighted_normal.c + * \ingroup modifiers + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_cdderivedmesh.h" +#include "BKE_deform.h" +#include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_mesh.h" + +#include "BLI_math.h" +#include "BLI_linklist.h" + +#include "MOD_modifiertypes.h" +#include "MOD_util.h" + +#define CLNORS_VALID_VEC_LEN (1e-6f) + +typedef struct ModePair { + float val; /* Contains mode based value (face area / corner angle). */ + int index; /* Index value per poly or per loop. */ +} ModePair; + +/* Sorting function used in modifier, sorts in decreasing order. */ +static int modepair_cmp_by_val_inverse(const void *p1, const void *p2) +{ + ModePair *r1 = (ModePair *)p1; + ModePair *r2 = (ModePair *)p2; + + return (r1->val < r2->val) ? 1 : ((r1->val > r2->val) ? -1 : 0); +} + +/* There will be one of those per vertex (simple case, computing one normal per vertex), or per smooth fan. */ +typedef struct WeightedNormalDataAggregateItem { + float normal[3]; + + int num_loops; /* Count number of loops using this item so far. */ + float curr_val; /* Current max val for this item. */ + int curr_strength; /* Current max strength encountered for this item. */ +} WeightedNormalDataAggregateItem; + +#define NUM_CACHED_INVERSE_POWERS_OF_WEIGHT 128 + +typedef struct WeightedNormalData { + const int numVerts; + const int numEdges; + const int numLoops; + const int numPolys; + + MVert *mvert; + MEdge *medge; + + MLoop *mloop; + short (*clnors)[2]; + const bool has_clnors; /* True if clnors already existed, false if we had to create them. */ + const float split_angle; + + MPoly *mpoly; + float (*polynors)[3]; + int *poly_strength; + + MDeformVert *dvert; + const int defgrp_index; + const bool use_invert_vgroup; + + const float weight; + const short mode; + + /* Lower-level, internal processing data. */ + float cached_inverse_powers_of_weight[NUM_CACHED_INVERSE_POWERS_OF_WEIGHT]; + + WeightedNormalDataAggregateItem *items_data; + + ModePair *mode_pair; + + int *loop_to_poly; +} WeightedNormalData; + +/* Check strength of given poly compared to those found so far for that given item (vertex or smooth fan), + * and reset matching item_data in case we get a stronger new strength. */ +static bool check_item_poly_strength( + WeightedNormalData *wn_data, WeightedNormalDataAggregateItem *item_data, const int mp_index) +{ + BLI_assert (wn_data->poly_strength != NULL); + + const int mp_strength = wn_data->poly_strength[mp_index]; + + if (mp_strength > item_data->curr_strength) { + item_data->curr_strength = mp_strength; + item_data->curr_val = 0.0f; + item_data->num_loops = 0; + zero_v3(item_data->normal); + } + + return mp_strength == item_data->curr_strength; +} + +static void aggregate_item_normal( + WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data, + WeightedNormalDataAggregateItem *item_data, + const int mv_index, const int mp_index, + const float curr_val, const bool use_face_influence) +{ + float (*polynors)[3] = wn_data->polynors; + + MDeformVert *dvert = wn_data->dvert; + const int defgrp_index = wn_data->defgrp_index; + const bool use_invert_vgroup = wn_data->use_invert_vgroup; + + const float weight = wn_data->weight; + + float *cached_inverse_powers_of_weight = wn_data->cached_inverse_powers_of_weight; + + const bool has_vgroup = dvert != NULL; + const bool vert_of_group = has_vgroup && defvert_find_index(&dvert[mv_index], defgrp_index) != NULL; + + if (has_vgroup && ((vert_of_group && use_invert_vgroup) || (!vert_of_group && !use_invert_vgroup))) { + return; + } + + if (use_face_influence && !check_item_poly_strength(wn_data, item_data, mp_index)) { + return; + } + + /* If item's curr_val is 0 init it to present value. */ + if (item_data->curr_val == 0.0f) { + item_data->curr_val = curr_val; + } + if (!compare_ff(item_data->curr_val, curr_val, wnmd->thresh)) { + /* item's curr_val and present value differ more than threshold, update. */ + item_data->num_loops++; + item_data->curr_val = curr_val; + } + + /* Exponentially divided weight for each normal (since a few values will be used by most cases, we cache those). */ + const int num_loops = item_data->num_loops; + if (num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT && cached_inverse_powers_of_weight[num_loops] == 0.0f) { + cached_inverse_powers_of_weight[num_loops] = 1.0f / powf(weight, num_loops); + } + const float inverted_n_weight = num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT ? + cached_inverse_powers_of_weight[num_loops] : 1.0f / powf(weight, num_loops); + + madd_v3_v3fl(item_data->normal, polynors[mp_index], curr_val * inverted_n_weight); +} + +static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) +{ + const int numVerts = wn_data->numVerts; + const int numEdges = wn_data->numEdges; + const int numLoops = wn_data->numLoops; + const int numPolys = wn_data->numPolys; + + MVert *mvert = wn_data->mvert; + MEdge *medge = wn_data->medge; + + MLoop *mloop = wn_data->mloop; + short (*clnors)[2] = wn_data->clnors; + int *loop_to_poly = wn_data->loop_to_poly; + + MPoly *mpoly = wn_data->mpoly; + float (*polynors)[3] = wn_data->polynors; + int *poly_strength = wn_data->poly_strength; + + MDeformVert *dvert = wn_data->dvert; + + const short mode = wn_data->mode; + ModePair *mode_pair = wn_data->mode_pair; + + const bool has_clnors = wn_data->has_clnors; + const float split_angle = wn_data->split_angle; + MLoopNorSpaceArray lnors_spacearr = {NULL}; + + const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0; + const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 && poly_strength != NULL; + const bool has_vgroup = dvert != NULL; + + float (*loop_normals)[3] = NULL; + + WeightedNormalDataAggregateItem *items_data = NULL; + int num_items = 0; + if (keep_sharp) { + BLI_bitmap *done_loops = BLI_BITMAP_NEW(numLoops, __func__); + + /* This will give us loop normal spaces, we do not actually care about computed loop_normals for now... */ + loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__); + BKE_mesh_normals_loop_split(mvert, numVerts, medge, numEdges, + mloop, loop_normals, numLoops, mpoly, polynors, numPolys, + true, split_angle, &lnors_spacearr, has_clnors ? clnors : NULL, loop_to_poly); + + num_items = lnors_spacearr.num_spaces; + items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__); + + /* In this first loop, we assign each WeightedNormalDataAggregateItem to its smooth fan of loops (aka lnor space). */ + MPoly *mp; + int mp_index; + int item_index; + for (mp = mpoly, mp_index = 0, item_index = 0; mp_index < numPolys; mp++, mp_index++) { + int ml_index = mp->loopstart; + const int ml_end_index = ml_index + mp->totloop; + + for (; ml_index < ml_end_index; ml_index++) { + if (BLI_BITMAP_TEST(done_loops, ml_index)) { + /* Smooth fan of this loop has already been processed, skip it. */ + continue; + } + BLI_assert(item_index < num_items); + + WeightedNormalDataAggregateItem *itdt = &items_data[item_index]; + itdt->curr_strength = FACE_STRENGTH_WEAK; + + MLoopNorSpace *lnor_space = lnors_spacearr.lspacearr[ml_index]; + lnor_space->user_data = itdt; + + if (!(lnor_space->flags & MLNOR_SPACE_IS_SINGLE)) { + for (LinkNode *lnode = lnor_space->loops; lnode; lnode = lnode->next) { + const int ml_fan_index = GET_INT_FROM_POINTER(lnode->link); + BLI_BITMAP_ENABLE(done_loops, ml_fan_index); + } + } + else { + BLI_BITMAP_ENABLE(done_loops, ml_index); + } + + item_index++; + } + } + + MEM_freeN(done_loops); + } + else { + num_items = numVerts; + items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__); + if (use_face_influence) { + for (int item_index = 0; item_index < num_items; item_index++) { + items_data[item_index].curr_strength = FACE_STRENGTH_WEAK; + } + } + } + wn_data->items_data = items_data; + + switch (mode) { + case MOD_WEIGHTEDNORMAL_MODE_FACE: + for (int i = 0; i < numPolys; i++) { + const int mp_index = mode_pair[i].index; + const float mp_val = mode_pair[i].val; + + int ml_index = mpoly[mp_index].loopstart; + const int ml_index_end = ml_index + mpoly[mp_index].totloop; + for (; ml_index < ml_index_end; ml_index++) { + const int mv_index = mloop[ml_index].v; + WeightedNormalDataAggregateItem *item_data = keep_sharp ? + lnors_spacearr.lspacearr[ml_index]->user_data: + &items_data[mv_index]; + + aggregate_item_normal(wnmd, wn_data, item_data, mv_index, mp_index, mp_val, use_face_influence); + } + } + break; + case MOD_WEIGHTEDNORMAL_MODE_ANGLE: + case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE: + BLI_assert(loop_to_poly != NULL); + + for (int i = 0; i < numLoops; i++) { + const int ml_index = mode_pair[i].index; + const float ml_val = mode_pair[i].val; + + const int mp_index = loop_to_poly[ml_index]; + const int mv_index = mloop[ml_index].v; + WeightedNormalDataAggregateItem *item_data = keep_sharp ? + lnors_spacearr.lspacearr[ml_index]->user_data: + &items_data[mv_index]; + + aggregate_item_normal(wnmd, wn_data, item_data, mv_index, mp_index, ml_val, use_face_influence); + } + break; + default: + BLI_assert(0); + } + + /* Validate computed weighted normals. */ + for (int item_index = 0; item_index < num_items; item_index++) { + if (normalize_v3(items_data[item_index].normal) < CLNORS_VALID_VEC_LEN) { + zero_v3(items_data[item_index].normal); + } + } + + if (keep_sharp) { + /* Set loop normals for normal computed for each lnor space (smooth fan). + * Note that loop_normals is already populated with clnors (before this modifier is applied, at start of + * this function), so no need to recompute them here. */ + for (int ml_index = 0; ml_index < numLoops; ml_index++) { + WeightedNormalDataAggregateItem *item_data = lnors_spacearr.lspacearr[ml_index]->user_data; + if (!is_zero_v3(item_data->normal)) { + copy_v3_v3(loop_normals[ml_index], item_data->normal); + } + } + + BKE_mesh_normals_loop_custom_set(mvert, numVerts, medge, numEdges, + mloop, loop_normals, numLoops, mpoly, polynors, numPolys, clnors); + } + else { + /* TODO: Ideally, we could add an option to BKE_mesh_normals_loop_custom_[from_vertices_]set() to keep current + * clnors instead of resetting them to default autocomputed ones, when given new custom normal is zero-vec. + * But this is not exactly trivial change, better to keep this optimization for later... + */ + if (!has_vgroup) { + /* Note: in theory, we could avoid this extra allocation & copying... But think we can live with it for now, + * and it makes code simpler & cleaner. */ + float (*vert_normals)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*loop_normals), __func__); + + for (int ml_index = 0; ml_index < numLoops; ml_index++) { + const int mv_index = mloop[ml_index].v; + copy_v3_v3(vert_normals[mv_index], items_data[mv_index].normal); + } + + BKE_mesh_normals_loop_custom_from_vertices_set(mvert, vert_normals, numVerts, medge, numEdges, + mloop, numLoops, mpoly, polynors, numPolys, clnors); + + MEM_freeN(vert_normals); + } + else { + loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__); + + BKE_mesh_normals_loop_split(mvert, numVerts, medge, numEdges, + mloop, loop_normals, numLoops, mpoly, polynors, numPolys, + true, split_angle, NULL, has_clnors ? clnors : NULL, loop_to_poly); + + for (int ml_index = 0; ml_index < numLoops; ml_index++) { + const int item_index = mloop[ml_index].v; + if (!is_zero_v3(items_data[item_index].normal)) { + copy_v3_v3(loop_normals[ml_index], items_data[item_index].normal); + } + } + + BKE_mesh_normals_loop_custom_set(mvert, numVerts, medge, numEdges, + mloop, loop_normals, numLoops, mpoly, polynors, numPolys, clnors); + } + } + + if (keep_sharp) { + BKE_lnor_spacearr_free(&lnors_spacearr); + } + MEM_SAFE_FREE(loop_normals); +} + +static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) +{ + const int numPolys = wn_data->numPolys; + + MVert *mvert = wn_data->mvert; + MLoop *mloop = wn_data->mloop; + MPoly *mpoly = wn_data->mpoly; + + MPoly *mp; + int mp_index; + + ModePair *face_area = MEM_malloc_arrayN((size_t)numPolys, sizeof(*face_area), __func__); + + ModePair *f_area = face_area; + for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++, f_area++) { + f_area->val = BKE_mesh_calc_poly_area(mp, &mloop[mp->loopstart], mvert); + f_area->index = mp_index; + } + + qsort(face_area, numPolys, sizeof(*face_area), modepair_cmp_by_val_inverse); + + wn_data->mode_pair = face_area; + apply_weights_vertex_normal(wnmd, wn_data); +} + +static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) +{ + const int numLoops = wn_data->numLoops; + const int numPolys = wn_data->numPolys; + + MVert *mvert = wn_data->mvert; + MLoop *mloop = wn_data->mloop; + MPoly *mpoly = wn_data->mpoly; + + MPoly *mp; + int mp_index; + + int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__); + + ModePair *corner_angle = MEM_malloc_arrayN((size_t)numLoops, sizeof(*corner_angle), __func__); + + for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) { + MLoop *ml_start = &mloop[mp->loopstart]; + + float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__); + BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle); + + ModePair *c_angl = &corner_angle[mp->loopstart]; + float *angl = index_angle; + for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; ml_index++, c_angl++, angl++) { + c_angl->val = (float)M_PI - *angl; + c_angl->index = ml_index; + + loop_to_poly[ml_index] = mp_index; + } + MEM_freeN(index_angle); + } + + qsort(corner_angle, numLoops, sizeof(*corner_angle), modepair_cmp_by_val_inverse); + + wn_data->loop_to_poly = loop_to_poly; + wn_data->mode_pair = corner_angle; + apply_weights_vertex_normal(wnmd, wn_data); +} + +static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) +{ + const int numLoops = wn_data->numLoops; + const int numPolys = wn_data->numPolys; + + MVert *mvert = wn_data->mvert; + MLoop *mloop = wn_data->mloop; + MPoly *mpoly = wn_data->mpoly; + + MPoly *mp; + int mp_index; + + int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__); + + ModePair *combined = MEM_malloc_arrayN((size_t)numLoops, sizeof(*combined), __func__); + + for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) { + MLoop *ml_start = &mloop[mp->loopstart]; + + float face_area = BKE_mesh_calc_poly_area(mp, ml_start, mvert); + float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__); + BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle); + + ModePair *cmbnd = &combined[mp->loopstart]; + float *angl = index_angle; + for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; ml_index++, cmbnd++, angl++) { + /* In this case val is product of corner angle and face area. */ + cmbnd->val = ((float)M_PI - *angl) * face_area; + cmbnd->index = ml_index; + + loop_to_poly[ml_index] = mp_index; + } + MEM_freeN(index_angle); + } + + qsort(combined, numLoops, sizeof(*combined), modepair_cmp_by_val_inverse); + + wn_data->loop_to_poly = loop_to_poly; + wn_data->mode_pair = combined; + apply_weights_vertex_normal(wnmd, wn_data); +} + +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) +{ + WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md; + Object *ob = ctx->object; + + /* XXX TODO ARG GRRR XYQWNMPRXTYY + * Once we fully switch to Mesh evaluation of modifiers, we can expect to get that flag from the COW copy. + * But for now, it is lost in the DM intermediate step, so we need to directly check orig object's data. */ +#if 0 + if (!(mesh->flag & ME_AUTOSMOOTH)) { +#else + if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) { +#endif + modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' option in mesh settings"); + return mesh; + } + + Mesh *result; + BKE_id_copy_ex( + NULL, &mesh->id, (ID **)&result, + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | + LIB_ID_COPY_NO_PREVIEW, + false); + + const int numVerts = result->totvert; + const int numEdges = result->totedge; + const int numLoops = result->totloop; + const int numPolys = result->totpoly; + + MEdge *medge = result->medge; + MPoly *mpoly = result->mpoly; + MVert *mvert = result->mvert; + MLoop *mloop = result->mloop; + + bool free_polynors = false; + + /* Right now: + * If weight = 50 then all faces are given equal weight. + * If weight > 50 then more weight given to faces with larger vals (face area / corner angle). + * If weight < 50 then more weight given to faces with lesser vals. However current calculation + * does not converge to min/max. + */ + float weight = ((float)wnmd->weight) / 50.0f; + if (wnmd->weight == 100) { + weight = (float)SHRT_MAX; + } + else if (wnmd->weight == 1) { + weight = 1 / (float)SHRT_MAX; + } + else if ((weight - 1) * 25 > 1) { + weight = (weight - 1) * 25; + } + + CustomData *pdata = &result->pdata; + float (*polynors)[3] = CustomData_get_layer(pdata, CD_NORMAL); + if (!polynors) { + polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys); + } + BKE_mesh_calc_normals_poly(mvert, NULL, numVerts, mloop, mpoly, numLoops, numPolys, polynors, false); + + + const float split_angle = mesh->smoothresh; + short (*clnors)[2]; + CustomData *ldata = &result->ldata; + clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL); + + /* Keep info whether we had clnors, it helps when generating clnor spaces and default normals. */ + const bool has_clnors = clnors != NULL; + if (!clnors) { + clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, numLoops); + clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL); + } + + MDeformVert *dvert; + int defgrp_index; + modifier_get_vgroup_mesh(ob, result, wnmd->defgrp_name, &dvert, &defgrp_index); + + WeightedNormalData wn_data = { + .numVerts = numVerts, + .numEdges = numEdges, + .numLoops = numLoops, + .numPolys = numPolys, + + .mvert = mvert, + .medge = medge, + + .mloop = mloop, + .clnors = clnors, + .has_clnors = has_clnors, + .split_angle = split_angle, + + .mpoly = mpoly, + .polynors = polynors, + .poly_strength = CustomData_get_layer_named(&result->pdata, CD_PROP_INT, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID), + + .dvert = dvert, + .defgrp_index = defgrp_index, + .use_invert_vgroup = (wnmd->flag & MOD_WEIGHTEDNORMAL_INVERT_VGROUP) != 0, + + .weight = weight, + .mode = wnmd->mode, + }; + + switch (wnmd->mode) { + case MOD_WEIGHTEDNORMAL_MODE_FACE: + wn_face_area(wnmd, &wn_data); + break; + case MOD_WEIGHTEDNORMAL_MODE_ANGLE: + wn_corner_angle(wnmd, &wn_data); + break; + case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE: + wn_face_with_angle(wnmd, &wn_data); + break; + } + + MEM_SAFE_FREE(wn_data.loop_to_poly); + MEM_SAFE_FREE(wn_data.mode_pair); + MEM_SAFE_FREE(wn_data.items_data); + + return result; +} + +static void initData(ModifierData *md) +{ + WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md; + wnmd->mode = MOD_WEIGHTEDNORMAL_MODE_FACE; + wnmd->weight = 50; + wnmd->thresh = 1e-2f; + wnmd->flag = 0; +} + +static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) +{ + WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md; + CustomDataMask dataMask = CD_CUSTOMLOOPNORMAL; + + if (wnmd->defgrp_name[0]) { + dataMask |= CD_MASK_MDEFORMVERT; + } + + if (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) { + dataMask |= CD_MASK_PROP_INT; + } + + return dataMask; +} + +static bool dependsOnNormals(ModifierData *UNUSED(md)) +{ + return true; +} + +ModifierTypeInfo modifierType_WeightedNormal = { + /* name */ "Weighted Normal", + /* structName */ "WeightedNormalModifierData", + /* structSize */ sizeof(WeightedNormalModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | + eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts_DM */ NULL, + /* deformMatrices_DM */ NULL, + /* deformVertsEM_DM */ NULL, + /* deformMatricesEM_DM*/NULL, + /* applyModifier_DM */ NULL, + /* applyModifierEM_DM */NULL, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + /* applyModifierEM */ NULL, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/tools b/source/tools index 6bcd05cf6aa..88a1758d2d2 160000 --- a/source/tools +++ b/source/tools @@ -1 +1 @@ -Subproject commit 6bcd05cf6aaafae07b8a15313d7fdda1471ff59e +Subproject commit 88a1758d2d2e862cc69c08b5b40a4e75f71592d3 -- cgit v1.2.3 From 9084c57a65854b5ac50583527ecd58ebf6f4f7c6 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Thu, 31 May 2018 14:42:50 +0530 Subject: Mark edges that can have seams in Bevel. Works by going clockwise from first edgehalf in BevVert and marking seam length each time it encounters a pair of edges with seams --- source/blender/bmesh/tools/bmesh_bevel.c | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index ca96e5b4b78..ad0e3b9c36e 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -150,6 +150,7 @@ 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 add_seam; // int _pad; } BoundVert; @@ -1522,6 +1523,38 @@ static void snap_to_superellipsoid(float co[3], const float super_r, bool midlin co[2] = z; } +#define BEV_SEAM(eh) (BM_elem_flag_test(eh->e, BM_ELEM_SEAM)) + +static void set_bound_vert_extend_seam_sharp_edges(BevVert *bv) +{ + EdgeHalf *e = &bv->edges[0], *efirst = &bv->edges[0]; + + while (!BEV_SEAM(e)) { + e = e->next; + if (e == efirst) + break; + } + if (!BEV_SEAM(e)) + return; + + efirst = e; + do { + int seam_length = 0; + EdgeHalf *ne = e->next; + + while (!BEV_SEAM(ne) && ne != efirst) { + if(ne->is_bev) + seam_length++; + ne = ne->next; + } + if (ne == e || (ne == efirst && !BEV_SEAM(efirst))) { + break; + } + e->rightv->add_seam = seam_length ? seam_length : 0; + e = ne; + } while (e != efirst); +} + /* Set the any_seam property for a BevVert and all its BoundVerts */ static void set_bound_vert_seams(BevVert *bv) { @@ -1539,6 +1572,8 @@ static void set_bound_vert_seams(BevVert *bv) } bv->any_seam |= v->any_seam; } while ((v = v->next) != bv->vmesh->boundstart); + + set_bound_vert_extend_seam_sharp_edges(bv); } static int count_bound_vert_seams(BevVert *bv) -- cgit v1.2.3 From 2f5704486d50f94619f02497475b344250d03213 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Fri, 1 Jun 2018 21:18:26 +0530 Subject: Added ability to apply seams to all middle edges between the 2 marked edges. currently does not make changes to material or sharpness of edges --- source/blender/bmesh/tools/bmesh_bevel.c | 49 +++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index ad0e3b9c36e..999639877a7 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -1555,6 +1555,51 @@ static void set_bound_vert_extend_seam_sharp_edges(BevVert *bv) } while (e != efirst); } +static void bevel_add_seams(BevVert *bv) +{ + VMesh *vm = bv->vmesh; + + BoundVert *bcur = bv->vmesh->boundstart, *start = bcur; + + do { + if (bcur->add_seam) { + if (!bv->vmesh->boundstart->add_seam && start == bv->vmesh->boundstart) + start = bcur; + + int idxlen = bcur->index + bcur->add_seam; + 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_SEAM, true); + 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_SEAM, true); + bcur = bcur->next; + } + } + else + bcur = bcur->next; + } while (bcur != start); +} + /* Set the any_seam property for a BevVert and all its BoundVerts */ static void set_bound_vert_seams(BevVert *bv) { @@ -5471,7 +5516,9 @@ void BM_mesh_bevel( BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - BLI_assert(find_bevvert(&bp, v) != NULL); + BevVert *bv = find_bevvert(&bp, v); + BLI_assert(bv != NULL); + bevel_add_seams(bv); BM_vert_kill(bm, v); } } -- cgit v1.2.3 From 79c0ac7c78878434aa01b54edbca9c7db6527831 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Sun, 3 Jun 2018 22:50:35 +0530 Subject: Added support for extending sharp edges with bevel --- source/blender/bmesh/tools/bmesh_bevel.c | 78 ++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 13 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 999639877a7..102d563c90c 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -151,6 +151,7 @@ typedef struct BoundVert { bool any_seam; /* are any of the edges attached here seams? */ bool visited; /* used during delta adjust pass */ int add_seam; + int sharp_len; // int _pad; } BoundVert; @@ -1523,39 +1524,49 @@ static void snap_to_superellipsoid(float co[3], const float super_r, bool midlin co[2] = z; } -#define BEV_SEAM(eh) (BM_elem_flag_test(eh->e, BM_ELEM_SEAM)) +#define EDGE_DATA_CHECK(eh, flag) (BM_elem_flag_test(eh->e, flag)) -static void set_bound_vert_extend_seam_sharp_edges(BevVert *bv) +static void check_edge_data(BevVert *bv, int flag, bool neg) { EdgeHalf *e = &bv->edges[0], *efirst = &bv->edges[0]; - while (!BEV_SEAM(e)) { + while (neg ^ !EDGE_DATA_CHECK(e, flag)) { e = e->next; if (e == efirst) break; } - if (!BEV_SEAM(e)) + if (neg ^ !EDGE_DATA_CHECK(e, flag)) return; efirst = e; do { - int seam_length = 0; + int flag_count = 0; EdgeHalf *ne = e->next; - - while (!BEV_SEAM(ne) && ne != efirst) { - if(ne->is_bev) - seam_length++; + + while ((neg ^ !EDGE_DATA_CHECK(ne, flag)) && ne != efirst) { + if (ne->is_bev) + flag_count++; ne = ne->next; } - if (ne == e || (ne == efirst && !BEV_SEAM(efirst))) { + if (ne == e || (ne == efirst && (neg ^ !EDGE_DATA_CHECK(efirst, flag)))) { break; } - e->rightv->add_seam = seam_length ? seam_length : 0; + if (flag == BM_ELEM_SEAM) + e->rightv->add_seam = flag_count; + else if (flag == BM_ELEM_SMOOTH) + e->rightv->sharp_len = flag_count; e = ne; } while (e != efirst); + } -static void bevel_add_seams(BevVert *bv) +static void set_bound_vert_extend_seam_sharp_edges(BevVert *bv) +{ + check_edge_data(bv, BM_ELEM_SEAM, false); + check_edge_data(bv, BM_ELEM_SMOOTH, true); +} + +static void bevel_extend_edge_data(BevVert *bv) { VMesh *vm = bv->vmesh; @@ -1598,6 +1609,47 @@ static void bevel_add_seams(BevVert *bv) 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); } /* Set the any_seam property for a BevVert and all its BoundVerts */ @@ -5518,7 +5570,7 @@ void BM_mesh_bevel( if (BM_elem_flag_test(v, BM_ELEM_TAG)) { BevVert *bv = find_bevvert(&bp, v); BLI_assert(bv != NULL); - bevel_add_seams(bv); + bevel_extend_edge_data(bv); BM_vert_kill(bm, v); } } -- cgit v1.2.3 From 2903146826a3e88bb9f001c7ce6678057fb7b1f3 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Mon, 4 Jun 2018 15:13:54 +0530 Subject: Added UI support for seams and sharp edges and cleanup --- .../startup/bl_ui/properties_data_modifier.py | 2 ++ source/blender/bmesh/intern/bmesh_opdefines.c | 2 ++ source/blender/bmesh/operators/bmo_bevel.c | 4 ++- source/blender/bmesh/tools/bmesh_bevel.c | 31 ++++++++++++---------- source/blender/bmesh/tools/bmesh_bevel.h | 2 +- source/blender/editors/mesh/editmesh_bevel.c | 28 +++++++++++++++++-- source/blender/makesdna/DNA_modifier_types.h | 8 +++++- source/blender/makesrna/intern/rna_modifier.c | 10 +++++++ source/blender/modifiers/intern/MOD_bevel.c | 5 +++- 9 files changed, 72 insertions(+), 20 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index abdf1ed2db1..45dda12f39b 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -140,6 +140,8 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "use_only_vertices") col.prop(md, "use_clamp_overlap") col.prop(md, "loop_slide") + col.prop(md, "mark_seam") + col.prop(md, "mark_sharp") layout.label(text="Limit Method:") layout.row().prop(md, "limit_method", expand=True) diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index b5e6fe168e5..e6a66372274 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1736,6 +1736,8 @@ 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}, + {"mark_sharp", BMO_OP_SLOT_BOOL}, {{'\0'}}, }, /* slots_out */ diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 2ae87b64286..cf063f7b0a8 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -43,6 +43,8 @@ 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"); if (offset > 0) { BMOIter siter; @@ -63,7 +65,7 @@ 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); 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/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 102d563c90c..8a2a022852d 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -202,6 +202,8 @@ 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 */ @@ -1526,7 +1528,7 @@ static void snap_to_superellipsoid(float co[3], const float super_r, bool midlin #define EDGE_DATA_CHECK(eh, flag) (BM_elem_flag_test(eh->e, flag)) -static void check_edge_data(BevVert *bv, int flag, bool neg) +static void check_edge_data_seam_sharp_edges(BevVert *bv, int flag, bool neg) { EdgeHalf *e = &bv->edges[0], *efirst = &bv->edges[0]; @@ -1560,12 +1562,6 @@ static void check_edge_data(BevVert *bv, int flag, bool neg) } -static void set_bound_vert_extend_seam_sharp_edges(BevVert *bv) -{ - check_edge_data(bv, BM_ELEM_SEAM, false); - check_edge_data(bv, BM_ELEM_SMOOTH, true); -} - static void bevel_extend_edge_data(BevVert *bv) { VMesh *vm = bv->vmesh; @@ -1653,7 +1649,7 @@ static void bevel_extend_edge_data(BevVert *bv) } /* 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; @@ -1670,7 +1666,12 @@ static void set_bound_vert_seams(BevVert *bv) bv->any_seam |= v->any_seam; } while ((v = v->next) != bv->vmesh->boundstart); - set_bound_vert_extend_seam_sharp_edges(bv); + 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) @@ -1741,7 +1742,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) @@ -1796,7 +1797,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); @@ -1855,7 +1856,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; @@ -1997,7 +1998,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; @@ -5481,7 +5482,7 @@ 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) { BMIter iter; BMVert *v, *v_next; @@ -5502,6 +5503,8 @@ 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; if (profile >= 0.999f) { /* r ~ 692, so PRO_SQUARE_R is 1e4 */ bp.pro_super_r = PRO_SQUARE_R; diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h index 386dc8a1fce..d932ac381a6 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.h +++ b/source/blender/bmesh/tools/bmesh_bevel.h @@ -33,6 +33,6 @@ 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); #endif /* __BMESH_BEVEL_H__ */ diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index e75b133b5bd..86aff48615c 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -224,6 +224,8 @@ static bool edbm_bevel_calc(wmOperator *op) const bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap"); int material = RNA_int_get(op->ptr, "material"); const bool loop_slide = RNA_boolean_get(op->ptr, "loop_slide"); + const bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam"); + const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { @@ -240,9 +242,9 @@ static bool edbm_bevel_calc(wmOperator *op) EDBM_op_init(em, &bmop, op, "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b " - "material=%i loop_slide=%b", + "material=%i loop_slide=%b mark_seam=%b mark_sharp=%b", BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, - clamp_overlap, material, loop_slide); + clamp_overlap, material, loop_slide, mark_seam, mark_sharp); BMO_op_exec(em->bm, &bmop); @@ -603,6 +605,26 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) edbm_bevel_update_header(C, op); handled = true; break; + case UKEY: + if (event->val == KM_RELEASE) + break; + else { + bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam"); + RNA_boolean_set(op->ptr, "mark_seam", !mark_seam); + edbm_bevel_calc(op); + handled = true; + break; + } + case KKEY: + if (event->val == KM_RELEASE) + break; + else { + bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); + RNA_boolean_set(op->ptr, "mark_sharp", !mark_sharp); + edbm_bevel_calc(op); + handled = true; + break; + } } @@ -666,6 +688,8 @@ void MESH_OT_bevel(wmOperatorType *ot) RNA_def_boolean(ot->srna, "clamp_overlap", false, "Clamp Overlap", "Do not allow beveled edges/vertices to overlap each other"); RNA_def_boolean(ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths"); + RNA_def_boolean(ot->srna, "mark_seam", false, "Mark Seams", "Mark Seams along beveled edges"); + RNA_def_boolean(ot->srna, "mark_sharp", false, "Mark Sharp", "Mark beveled edges as sharp"); RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100); } diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 1d7d1b34f6b..433d75706bb 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -328,7 +328,7 @@ typedef struct BevelModifierData { short lim_flags; /* flags to tell the tool how to limit the bevel */ short e_flags; /* flags to direct how edge weights are applied to verts */ short mat; /* material index if >= 0, else material inherited from surrounding faces */ - short pad; + short edge_flags; int pad2; float profile; /* controls profile shape (0->1, .5 is round) */ /* if the MOD_BEVEL_ANGLE is set, this will be how "sharp" an edge must be before it gets beveled */ @@ -365,6 +365,12 @@ enum { MOD_BEVEL_AMT_PERCENT = 3, }; +/* BevelModifierData->edge_flags */ +enum { + MOD_BEVEL_MARK_SEAM = (1 << 0), + MOD_BEVEL_MARK_SHARP = (1 << 1), +}; + typedef struct SmokeModifierData { ModifierData modifier; diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index c665442a82f..a9bf7b18f73 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -3104,6 +3104,16 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) RNA_def_property_boolean_negative_sdna(prop, NULL, "flags", MOD_BEVEL_EVEN_WIDTHS); RNA_def_property_ui_text(prop, "Loop Slide", "Prefer sliding along edges to having even widths"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "mark_seam", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "edge_flags", MOD_BEVEL_MARK_SEAM); + RNA_def_property_ui_text(prop, "Mark Seams", "Mark Seams along beveled edges"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "mark_sharp", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "edge_flags", MOD_BEVEL_MARK_SHARP); + RNA_def_property_ui_text(prop, "Mark Sharp", "Mark beveled edges as sharp"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_shrinkwrap(BlenderRNA *brna) diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 81a4e94386f..61ecc5c734e 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -59,6 +59,7 @@ static void initData(ModifierData *md) bmd->val_flags = MOD_BEVEL_AMT_OFFSET; bmd->lim_flags = 0; bmd->e_flags = 0; + bmd->edge_flags = 0; bmd->mat = -1; bmd->profile = 0.5f; bmd->bevel_angle = DEG2RADF(30.0f); @@ -96,6 +97,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes const int offset_type = bmd->val_flags; const int mat = CLAMPIS(bmd->mat, -1, ctx->object->totcol - 1); const bool loop_slide = (bmd->flags & MOD_BEVEL_EVEN_WIDTHS) == 0; + const bool mark_seam = (bmd->edge_flags & MOD_BEVEL_MARK_SEAM); + const bool mark_sharp = (bmd->edge_flags & MOD_BEVEL_MARK_SHARP); bm = BKE_mesh_to_bmesh_ex( mesh, @@ -166,7 +169,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes BM_mesh_bevel(bm, bmd->value, offset_type, bmd->res, bmd->profile, vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp, - dvert, vgroup, mat, loop_slide); + dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp); result = BKE_bmesh_to_mesh_nomain(bm, &(struct BMeshToMeshParams){0}); -- cgit v1.2.3 From 18a8bb5c16f9a14dafbdcbec328c334416541425 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Tue, 5 Jun 2018 23:21:08 +0530 Subject: Fix compilation error due to different params in freeCustomNormalArray declaration and definition --- source/blender/editors/transform/transform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 3718f1be9a8..62356cd4ba6 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -875,7 +875,7 @@ bool applyTransformOrientation(const struct TransformOrientation *ts, float r_ma int getTransformOrientation_ex(const struct bContext *C, float normal[3], float plane[3], const short around); int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3]); -void freeCustomNormalArray(TransInfo *t, TransCustomData *custom_data); +void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data); void freeEdgeSlideTempFaces(EdgeSlideData *sld); void freeEdgeSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data); -- cgit v1.2.3 From 0c6410ec0cffdcb0641fa85d8394f7c682c44143 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Mon, 11 Jun 2018 11:58:26 +0530 Subject: Added ability to harden normals. Uses 2 different params: mode and strength. There are still some hiccups with how 2.8 interacts with normals. Will resolve as support gets better --- source/blender/bmesh/intern/bmesh_mesh.c | 35 +++++++++ source/blender/bmesh/intern/bmesh_mesh.h | 1 + source/blender/bmesh/intern/bmesh_opdefines.c | 3 + source/blender/bmesh/intern/bmesh_operators.h | 5 ++ source/blender/bmesh/operators/bmo_bevel.c | 3 +- source/blender/bmesh/tools/bmesh_bevel.c | 87 ++++++++++++++++++++-- source/blender/bmesh/tools/bmesh_bevel.h | 3 +- source/blender/editors/mesh/editmesh_bevel.c | 100 +++++++++++++++++++++++++- source/blender/editors/mesh/editmesh_tools.c | 41 +---------- source/blender/makesdna/DNA_modifier_types.h | 8 +++ source/blender/makesrna/intern/rna_modifier.c | 17 +++++ source/blender/modifiers/intern/MOD_bevel.c | 2 +- 12 files changed, 258 insertions(+), 47 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index 79c835cca11..3a4aec8cc69 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -1225,6 +1225,41 @@ void BM_lnorspace_update(BMesh *bm) } } +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; + } + + 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 diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h index 44887e81157..43029e370c6 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.h +++ b/source/blender/bmesh/intern/bmesh_mesh.h @@ -59,6 +59,7 @@ 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 diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index e6a66372274..49d160f5d4a 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1738,12 +1738,15 @@ static BMOpDefine bmo_bevel_def = { {"loop_slide", BMO_OP_SLOT_BOOL}, /* prefer to slide along edges to having even widths */ {"mark_seam", BMO_OP_SLOT_BOOL}, {"mark_sharp", BMO_OP_SLOT_BOOL}, + {"strength", BMO_OP_SLOT_FLT}, + {"hnmode", BMO_OP_SLOT_INT}, {{'\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}, {{'\0'}}, }, diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h index 80b57eb3565..3ae9a77a761 100644 --- a/source/blender/bmesh/intern/bmesh_operators.h +++ b/source/blender/bmesh/intern/bmesh_operators.h @@ -127,6 +127,11 @@ enum { BEVEL_AMT_PERCENT }; +enum { + BEVEL_HN_FACE, + BEVEL_HN_ADJ, +}; + extern const BMOpDefine *bmo_opdefines[]; extern const int bmo_opdefines_total; diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index cf063f7b0a8..cd27b486929 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -45,6 +45,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) 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; @@ -65,7 +66,7 @@ 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, mark_seam, mark_sharp); + BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, clamp_overlap, NULL, -1, material, loop_slide, mark_seam, mark_sharp, 0/*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/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 8a2a022852d..18039261735 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -37,6 +37,7 @@ #include "BLI_array.h" #include "BLI_alloca.h" +#include "BLI_bitmap.h" #include "BLI_gsqueue.h" #include "BLI_math.h" #include "BLI_memarena.h" @@ -207,6 +208,7 @@ typedef struct BevelParams { 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" @@ -1648,6 +1650,76 @@ static void bevel_extend_edge_data(BevVert *bv) } while (bcur != start); } +static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, BMOperator *op) +{ + int mode = 1; + + VMesh *vm = bv->vmesh; + BoundVert *bcur = vm->boundstart, *bstart = bcur; + int ns = vm->seg, ns2 = ns / 2; + + 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) { + BLI_bitmap *faces = BLI_BITMAP_NEW(bm->totface, __func__); + 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_BITMAP_TEST(faces, 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_BITMAP_ENABLE(faces, BM_elem_index_get(f_a)); + } + if (f_b && !BLI_BITMAP_TEST(faces, 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_BITMAP_ENABLE(faces, BM_elem_index_get(f_b)); + } + } + } + MEM_freeN(faces); + 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 { + if (BMO_slot_map_contains(nslot, bcur->nv.v) != true) { + + float(*custom_normal) = MEM_callocN(sizeof(*custom_normal) * 3, __func__); + add_v3_v3(custom_normal, n_final); + normalize_v3(custom_normal); + + BMO_slot_map_insert(op, nslot, bcur->nv.v, custom_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, bool mark_seam, bool mark_sharp) { @@ -5482,7 +5554,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 mark_seam, const bool mark_sharp) + const bool loop_slide, const bool mark_seam, const bool mark_sharp, + const int hnmode, BMOperator *op) { BMIter iter; BMVert *v, *v_next; @@ -5505,6 +5578,7 @@ void BM_mesh_bevel( bp.mat_nr = mat; bp.mark_seam = mark_seam; bp.mark_sharp = mark_sharp; + bp.hnmode = hnmode; if (profile >= 0.999f) { /* r ~ 692, so PRO_SQUARE_R is 1e4 */ bp.pro_super_r = PRO_SQUARE_R; @@ -5561,6 +5635,13 @@ void BM_mesh_bevel( } } + GHASH_ITER(giter, bp.vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + bevel_extend_edge_data(bv); + if(bm->use_toolflags) + bevel_harden_normals_mode(bm, &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)) { @@ -5571,9 +5652,7 @@ void BM_mesh_bevel( BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - BevVert *bv = find_bevvert(&bp, v); - BLI_assert(bv != NULL); - bevel_extend_edge_data(bv); + BLI_assert(find_bevvert(&bp, v) != NULL); BM_vert_kill(bm, v); } } diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h index d932ac381a6..f43289aac27 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 bool mark_seam, const bool mark_sharp); + const int mat, const bool loop_slide, const bool mark_seam, const bool mark_sharp, + const int hnmode, BMOperator *op); #endif /* __BMESH_BEVEL_H__ */ diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 86aff48615c..859b0942e55 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -30,6 +30,7 @@ #include "BLI_string.h" #include "BLI_math.h" +#include "BLI_linklist_stack.h" #include "BLT_translation.h" @@ -38,6 +39,7 @@ #include "BKE_editmesh.h" #include "BKE_unit.h" #include "BKE_layer.h" +#include "BKE_mesh.h" #include "RNA_define.h" #include "RNA_access.h" @@ -134,6 +136,88 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op) } } +static void bevel_harden_normals(BMEditMesh *em, BMOperator *bmop, float face_strength, int hnmode) +{ + BKE_editmesh_lnorspace_update(em); + BM_normals_loops_edges_tag(em->bm, true); + int cd_clnors_offset = CustomData_get_offset(&em->bm->ldata, CD_CUSTOMLOOPNORMAL); + + BMesh *bm = em->bm; + BMFace *f; + BMLoop *l, *l_cur, *l_first; + BMIter fiter; + + BMOpSlot *nslot = BMO_slot_get(bmop->slots_out, "normals.out"); + + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + l_cur = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_elem_flag_test(l_cur->v, BM_ELEM_SELECT) && (!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) || + (!BM_elem_flag_test(l_cur, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_cur)))) + { + if (!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_cur->prev->e, BM_ELEM_TAG)) { + const int loop_index = BM_elem_index_get(l_cur); + short *clnors = BM_ELEM_CD_GET_VOID_P(l_cur, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors); + } + else { + BMVert *v_pivot = l_cur->v; + float *calc_n = BLI_ghash_lookup(nslot->data.ghash, v_pivot); + + BMEdge *e_next; + const BMEdge *e_org = l_cur->e; + BMLoop *lfan_pivot, *lfan_pivot_next; + + lfan_pivot = l_cur; + e_next = lfan_pivot->e; + BLI_SMALLSTACK_DECLARE(loops, BMLoop *); + float cn_wght[3] = { 0.0f, 0.0f, 0.0f }, cn_unwght[3] = { 0.0f, 0.0f, 0.0f }; + + while (true) { + lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); + if (lfan_pivot_next) { + BLI_assert(lfan_pivot_next->v == v_pivot); + } + else { + e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e; + } + BLI_SMALLSTACK_PUSH(loops, lfan_pivot); + float cur[3]; + mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f)); + add_v3_v3(cn_wght, cur); + if(BM_elem_flag_test(lfan_pivot->f, BM_ELEM_SELECT)) + add_v3_v3(cn_unwght, cur); + + if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { + break; + } + lfan_pivot = lfan_pivot_next; + } + + normalize_v3(cn_wght); + normalize_v3(cn_unwght); + if (calc_n) { + mul_v3_fl(calc_n, face_strength); + mul_v3_fl(cn_wght, 1.0f - face_strength); + add_v3_v3(calc_n, cn_wght); + normalize_v3(calc_n); + } + while ((l = BLI_SMALLSTACK_POP(loops))) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + if (calc_n) { + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], calc_n, clnors); + } + else + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], cn_unwght, clnors); + } + BLI_ghash_remove(nslot->data.ghash, v_pivot, NULL, MEM_freeN); + } + } + } while ((l_cur = l_cur->next) != l_first); + } +} + static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) { Scene *scene = CTX_data_scene(C); @@ -226,6 +310,8 @@ static bool edbm_bevel_calc(wmOperator *op) const bool loop_slide = RNA_boolean_get(op->ptr, "loop_slide"); const bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam"); const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); + const float strength = RNA_float_get(op->ptr, "strength"); + const int hnmode = RNA_enum_get(op->ptr, "hnmode"); for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { @@ -242,9 +328,9 @@ static bool edbm_bevel_calc(wmOperator *op) EDBM_op_init(em, &bmop, op, "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b " - "material=%i loop_slide=%b mark_seam=%b mark_sharp=%b", + "material=%i loop_slide=%b mark_seam=%b mark_sharp=%b strength=%f hnmode=%i", BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, - clamp_overlap, material, loop_slide, mark_seam, mark_sharp); + clamp_overlap, material, loop_slide, mark_seam, mark_sharp, strength, hnmode); BMO_op_exec(em->bm, &bmop); @@ -255,6 +341,8 @@ static bool edbm_bevel_calc(wmOperator *op) BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); } + bevel_harden_normals(em, &bmop, strength, hnmode); + /* no need to de-select existing geometry */ if (!EDBM_op_finish(em, &bmop, op, true)) { continue; @@ -663,6 +751,12 @@ void MESH_OT_bevel(wmOperatorType *ot) {0, NULL, 0, NULL, NULL}, }; + static EnumPropertyItem harden_normals_items[] = { + { BEVEL_HN_FACE, "HN_FACE", 0, "Face Area", "Use faces as weight" }, + { BEVEL_HN_ADJ, "HN_ADJ", 0, "Vertex average", "Use adjacent vertices as weight" }, + { 0, NULL, 0, NULL, NULL }, + }; + /* identifiers */ ot->name = "Bevel"; ot->description = "Edge Bevel"; @@ -692,4 +786,6 @@ void MESH_OT_bevel(wmOperatorType *ot) RNA_def_boolean(ot->srna, "mark_sharp", false, "Mark Sharp", "Mark beveled edges as sharp"); RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100); + RNA_def_float(ot->srna, "strength", 0.5f, 0.0f, 1.0f, "Normal Strength", "Strength of calculated normal", 0.0f, 1.0f); + RNA_def_enum(ot->srna, "hnmode", harden_normals_items, BEVEL_HN_FACE, "Normal Mode", "Weighting mode for Harden Normals"); } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 07812cefb6b..afa89b11974 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -7426,41 +7426,6 @@ void MESH_OT_point_normals(struct wmOperatorType *ot) /********************** Split/Merge Loop Normals **********************/ -static void normals_splitmerge_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; - } - - 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); -} - static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr) { BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; @@ -7469,7 +7434,7 @@ static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr) BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); - normals_splitmerge_loops_edges_tag(bm, false); + BM_normals_loops_edges_tag(bm, false); for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { if (BM_elem_flag_test(lnor_ed->loop, BM_ELEM_TAG)) { @@ -7512,7 +7477,7 @@ static void normals_split(BMesh *bm) BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); - normals_splitmerge_loops_edges_tag(bm, true); + BM_normals_loops_edges_tag(bm, true); const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { @@ -7695,7 +7660,7 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op) weight = (weight - 1) * 25; } - normals_splitmerge_loops_edges_tag(bm, true); + BM_normals_loops_edges_tag(bm, true); Heap *loop_weight = BLI_heap_new(); diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 433d75706bb..2400069a49a 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -334,6 +334,8 @@ typedef struct BevelModifierData { /* if the MOD_BEVEL_ANGLE is set, this will be how "sharp" an edge must be before it gets beveled */ float bevel_angle; /* if the MOD_BEVEL_VWEIGHT option is set, this will be the name of the vert group, MAX_VGROUP_NAME */ + int hnmode; + float strength; char defgrp_name[64]; } BevelModifierData; @@ -371,6 +373,12 @@ enum { MOD_BEVEL_MARK_SHARP = (1 << 1), }; +/* BevelModifierData->hnmode */ +enum { + MOD_BEVEL_HN_FACE, + MOD_BEVEL_HN_ADJ, +}; + typedef struct SmokeModifierData { ModifierData modifier; diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index a9bf7b18f73..37bb54cbe9e 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -3028,6 +3028,12 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_harden_normals_items[] = { + { MOD_BEVEL_HN_FACE, "HN_FACE", 0, "Face Area", "Use faces as weight" }, + { MOD_BEVEL_HN_ADJ, "HN_ADJ", 0, "Vertex average", "Use adjacent vertices as weight" }, + { 0, NULL, 0, NULL, NULL }, + }; + srna = RNA_def_struct(brna, "BevelModifier", "Modifier"); RNA_def_struct_ui_text(srna, "Bevel Modifier", "Bevel modifier to make edges and vertices more rounded"); RNA_def_struct_sdna(srna, "BevelModifierData"); @@ -3114,6 +3120,17 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "edge_flags", MOD_BEVEL_MARK_SHARP); RNA_def_property_ui_text(prop, "Mark Sharp", "Mark beveled edges as sharp"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "hnmode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, prop_harden_normals_items); + RNA_def_property_ui_text(prop, "Normal Mode", "Weighting mode for Harden Normals"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0, 10); + RNA_def_property_ui_range(prop, 0, 10, 1, 2); + RNA_def_property_ui_text(prop, "Normal Strength", "Strength of calculated normal"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_shrinkwrap(BlenderRNA *brna) diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 61ecc5c734e..4df8f1d06ae 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -169,7 +169,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes BM_mesh_bevel(bm, bmd->value, offset_type, bmd->res, bmd->profile, vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp, - dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp); + dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp, bmd->hnmode, NULL); result = BKE_bmesh_to_mesh_nomain(bm, &(struct BMeshToMeshParams){0}); -- cgit v1.2.3 From 29221319716d6588a2ad27977a1a6d86dcd96c37 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Wed, 13 Jun 2018 21:53:15 +0530 Subject: Corrected bevel of vertex by using profiles for curve of bevel --- release/scripts/addons | 2 +- release/scripts/addons_contrib | 2 +- source/blender/bmesh/tools/bmesh_bevel.c | 11 +++++++++++ source/tools | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/release/scripts/addons b/release/scripts/addons index ebd058d7a64..27970761a18 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit ebd058d7a6438d137522063bb3286c8acc325ca6 +Subproject commit 27970761a18926abe1b0020aa350305e3109a537 diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib index 47470215783..6a4f93c9b8f 160000 --- a/release/scripts/addons_contrib +++ b/release/scripts/addons_contrib @@ -1 +1 @@ -Subproject commit 474702157831f1a58bb50f5240ab8b1b02b6ba37 +Subproject commit 6a4f93c9b8f36b19bd02087abf3d7f5983df035a diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 39ca5a2d1ca..0fdf3a8868c 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -3647,6 +3647,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); diff --git a/source/tools b/source/tools index 9d7d338cb25..88a1758d2d2 160000 --- a/source/tools +++ b/source/tools @@ -1 +1 @@ -Subproject commit 9d7d338cb25a071f9646cf9ba16f17004c963f77 +Subproject commit 88a1758d2d2e862cc69c08b5b40a4e75f71592d3 -- cgit v1.2.3 From e5880eb1ffdccc3295ca6a27fec8bb55fd20c27d Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Wed, 13 Jun 2018 21:56:15 +0530 Subject: Fix exception in superellipse where precision_reached is used with proper initialization --- source/blender/bmesh/tools/bmesh_bevel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 0fdf3a8868c..148196ec505 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -5146,7 +5146,7 @@ static void find_even_superellipse_chords_general(int seg, float r, double *xval double sum; double temp; - bool precision_reached; + bool precision_reached = true; /* Exception: var used without being initialized */ bool seg_odd = seg % 2; bool rbig; -- cgit v1.2.3 From dd752476b97aa3b35d1359422ca42e33d99ac851 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Tue, 19 Jun 2018 19:27:08 +0530 Subject: Added face strength in bevel modifier The selected face strength (Weak/Medium/High) can be used by the WN Modifier to determine influence of current face in --- .../startup/bl_ui/properties_data_modifier.py | 2 ++ source/blender/bmesh/tools/bmesh_bevel.c | 1 + source/blender/makesdna/DNA_modifier_types.h | 3 ++- source/blender/makesrna/intern/rna_modifier.c | 7 +++++- source/blender/modifiers/intern/MOD_bevel.c | 29 ++++++++++++++++++++++ 5 files changed, 40 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index acd1edc022a..428c45697a3 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -142,6 +142,8 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "loop_slide") col.prop(md, "mark_seam") col.prop(md, "mark_sharp") + + col.prop(md, "set_wn_strength") layout.label(text="Limit Method:") layout.row().prop(md, "limit_method", expand=True) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 148196ec505..d8a7f59cf65 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -5661,6 +5661,7 @@ void BM_mesh_bevel( } } + BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { BLI_assert(find_bevvert(&bp, v) != NULL); diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 2400069a49a..3cf1d9f30f2 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -335,7 +335,7 @@ typedef struct BevelModifierData { float bevel_angle; /* if the MOD_BEVEL_VWEIGHT option is set, this will be the name of the vert group, MAX_VGROUP_NAME */ int hnmode; - float strength; + float hn_strength; char defgrp_name[64]; } BevelModifierData; @@ -357,6 +357,7 @@ enum { /* MOD_BEVEL_DIST = (1 << 12), */ /* same as above */ MOD_BEVEL_OVERLAP_OK = (1 << 13), MOD_BEVEL_EVEN_WIDTHS = (1 << 14), + MOD_BEVEL_SET_WN_STR = (1 << 15), }; /* BevelModifierData->val_flags (not used as flags any more) */ diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 04d8613c8d8..568b5b81ade 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -3127,11 +3127,16 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Normal Mode", "Weighting mode for Harden Normals"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); - prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "hn_strength", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0, 10); RNA_def_property_ui_range(prop, 0, 10, 1, 2); RNA_def_property_ui_text(prop, "Normal Strength", "Strength of calculated normal"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "set_wn_strength", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_BEVEL_SET_WN_STR); + RNA_def_property_ui_text(prop, "Face Strength", "Set face strength of beveled faces for use in WN Modifier"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_shrinkwrap(BlenderRNA *brna) diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 4df8f1d06ae..7a20eb005f3 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -34,6 +34,7 @@ #include "DNA_object_types.h" #include "DNA_mesh_types.h" +#include "DNA_scene_types.h" #include "BLI_utildefines.h" #include "BLI_math.h" @@ -77,6 +78,30 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) return dataMask; } +static void bevel_set_weighted_normal_face_strength(BMesh *bm, Scene *scene) +{ + BMFace *f; + BMIter fiter; + const char *wn_layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID; + int cd_prop_int_idx = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, wn_layer_id); + + if (cd_prop_int_idx == -1) { + BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, wn_layer_id); + cd_prop_int_idx = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, wn_layer_id); + } + cd_prop_int_idx -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT); + const int cd_prop_int_offset = CustomData_get_n_offset(&bm->pdata, CD_PROP_INT, cd_prop_int_idx); + + const int face_strength = scene->toolsettings->face_strength; + + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG)) { + int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset); + *strength = face_strength; + } + } +} + /* * This calls the new bevel code (added since 2.64) */ @@ -99,6 +124,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes const bool loop_slide = (bmd->flags & MOD_BEVEL_EVEN_WIDTHS) == 0; const bool mark_seam = (bmd->edge_flags & MOD_BEVEL_MARK_SEAM); const bool mark_sharp = (bmd->edge_flags & MOD_BEVEL_MARK_SHARP); + const bool set_wn_strength = (bmd->flags & MOD_BEVEL_SET_WN_STR); bm = BKE_mesh_to_bmesh_ex( mesh, @@ -171,6 +197,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp, dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp, bmd->hnmode, NULL); + if(set_wn_strength) + bevel_set_weighted_normal_face_strength(bm, md->scene); + result = BKE_bmesh_to_mesh_nomain(bm, &(struct BMeshToMeshParams){0}); BLI_assert(bm->vtoolflagpool == NULL && -- cgit v1.2.3 From 0f66fe5732d7b6260b39e7aef9e406783c20b796 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Fri, 22 Jun 2018 23:22:44 +0530 Subject: Fix normal shading continuity for in-plane bevels --- source/blender/bmesh/tools/bmesh_bevel.c | 32 +++++++++++++++++++++----------- source/tools | 2 +- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index d8a7f59cf65..c63fe69762a 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -3124,29 +3124,34 @@ 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; 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) @@ -3157,7 +3162,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; @@ -3190,9 +3195,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); @@ -3667,7 +3677,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 */ diff --git a/source/tools b/source/tools index 87f7038ee8c..88a1758d2d2 160000 --- a/source/tools +++ b/source/tools @@ -1 +1 @@ -Subproject commit 87f7038ee8c4b46a5e73a1a9065e2a9b7367f594 +Subproject commit 88a1758d2d2e862cc69c08b5b40a4e75f71592d3 -- cgit v1.2.3 From 1757b381790cd490e14b7ff7b6c4c84e4f1132e9 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Sat, 23 Jun 2018 01:46:42 +0530 Subject: Added UI for harden normals and normal control in bevel modifier --- .../startup/bl_ui/properties_data_modifier.py | 8 +- source/blender/bmesh/intern/bmesh_operators.h | 1 + source/blender/editors/mesh/editmesh_bevel.c | 1 + source/blender/makesdna/DNA_modifier_types.h | 1 + source/blender/makesrna/intern/rna_modifier.c | 5 +- source/blender/modifiers/intern/MOD_bevel.c | 109 +++++++++++++++++++++ 6 files changed, 121 insertions(+), 4 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 581f3ca91bc..b79e594095d 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -143,8 +143,6 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "mark_seam") col.prop(md, "mark_sharp") - col.prop(md, "set_wn_strength") - layout.label(text="Limit Method:") layout.row().prop(md, "limit_method", expand=True) if md.limit_method == 'ANGLE': @@ -155,6 +153,12 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): layout.label(text="Width Method:") layout.row().prop(md, "offset_type", expand=True) + + layout.label(text="Normal Mode") + layout.row().prop(md, "hnmode", expand=True) + layout.prop(md, "hn_strength") + layout.prop(md, "set_wn_strength") + def BOOLEAN(self, layout, ob, md): split = layout.split() diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h index 3ae9a77a761..1b5694c3ee8 100644 --- a/source/blender/bmesh/intern/bmesh_operators.h +++ b/source/blender/bmesh/intern/bmesh_operators.h @@ -128,6 +128,7 @@ enum { }; enum { + BEVEL_HN_NONE, BEVEL_HN_FACE, BEVEL_HN_ADJ, }; diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 1daf020dc7b..40be91aada1 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -752,6 +752,7 @@ void MESH_OT_bevel(wmOperatorType *ot) }; static EnumPropertyItem harden_normals_items[] = { + { BEVEL_HN_NONE, "HN_NONE", 0, "Off", "Do not use Harden Normals" }, { BEVEL_HN_FACE, "HN_FACE", 0, "Face Area", "Use faces as weight" }, { BEVEL_HN_ADJ, "HN_ADJ", 0, "Vertex average", "Use adjacent vertices as weight" }, { 0, NULL, 0, NULL, NULL }, diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 891f854c9eb..83f98c1181e 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -376,6 +376,7 @@ enum { /* BevelModifierData->hnmode */ enum { + MOD_BEVEL_HN_NONE, MOD_BEVEL_HN_FACE, MOD_BEVEL_HN_ADJ, }; diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index c29e40cba56..497125476a2 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -3025,6 +3025,7 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) }; static EnumPropertyItem prop_harden_normals_items[] = { + { MOD_BEVEL_HN_NONE, "HN_NONE", 0, "Off", "Do not use Harden Normals" }, { MOD_BEVEL_HN_FACE, "HN_FACE", 0, "Face Area", "Use faces as weight" }, { MOD_BEVEL_HN_ADJ, "HN_ADJ", 0, "Vertex average", "Use adjacent vertices as weight" }, { 0, NULL, 0, NULL, NULL }, @@ -3123,8 +3124,8 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "hn_strength", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0, 10); - RNA_def_property_ui_range(prop, 0, 10, 1, 2); + RNA_def_property_range(prop, 0, 1); + RNA_def_property_ui_range(prop, 0, 1, 1, 2); RNA_def_property_ui_text(prop, "Normal Strength", "Strength of calculated normal"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 6902b811c26..77b306466c3 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -32,11 +32,14 @@ * \ingroup modifiers */ +#include "MEM_guardedalloc.h" + #include "DNA_object_types.h" #include "DNA_mesh_types.h" #include "DNA_scene_types.h" #include "BLI_utildefines.h" +#include "BLI_linklist_stack.h" #include "BLI_math.h" #include "BLI_string.h" @@ -102,6 +105,109 @@ static void bevel_set_weighted_normal_face_strength(BMesh *bm, Scene *scene) } } +static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn_strength, int hnmode, MDeformVert *dvert, int vgroup) +{ + if (bmd->res > 20) + return; + BM_mesh_normals_update(bm); + BM_lnorspace_update(bm); + BM_normals_loops_edges_tag(bm, true); + + int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + + BMFace *f; + BMLoop *l, *l_cur, *l_first; + BMIter fiter; + + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + l_cur = l_first = BM_FACE_FIRST_LOOP(f); + do { + if ((!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) || (!BM_elem_flag_test(l_cur, BM_ELEM_TAG) && + BM_loop_check_cyclic_smooth_fan(l_cur)))) { + + if (!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_cur->prev->e, BM_ELEM_TAG)) { + const int loop_index = BM_elem_index_get(l_cur); + short *clnors = BM_ELEM_CD_GET_VOID_P(l_cur, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors); + } + else { + BMVert *v_pivot = l_cur->v; + BMEdge *e_next; + const BMEdge *e_org = l_cur->e; + BMLoop *lfan_pivot, *lfan_pivot_next; + + lfan_pivot = l_cur; + e_next = lfan_pivot->e; + BLI_SMALLSTACK_DECLARE(loops, BMLoop *); + float cn_wght[3] = { 0.0f, 0.0f, 0.0f }; + + while (true) { + lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); + if (lfan_pivot_next) { + BLI_assert(lfan_pivot_next->v == v_pivot); + } + else { + e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e; + } + + BLI_SMALLSTACK_PUSH(loops, lfan_pivot); + + if (bmd->lim_flags & MOD_BEVEL_WEIGHT) { + int weight = BM_elem_float_data_get(&bm->edata, lfan_pivot->f, CD_BWEIGHT); + if (weight) { + if (bmd->hnmode == MOD_BEVEL_HN_FACE) { + float cur[3]; + mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f)); + add_v3_v3(cn_wght, cur); + } + else + add_v3_v3(cn_wght, lfan_pivot->f->no); + } + else + add_v3_v3(cn_wght, lfan_pivot->f->no); + + } + else if (bmd->lim_flags & MOD_BEVEL_VGROUP) { + const bool has_vgroup = dvert != NULL; + const bool vert_of_group = has_vgroup && defvert_find_index(&dvert[BM_elem_index_get(l->v)], vgroup) != NULL; + if (vert_of_group && bmd->hnmode == MOD_BEVEL_HN_FACE) { + float cur[3]; + mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f)); + add_v3_v3(cn_wght, cur); + } + else + add_v3_v3(cn_wght, lfan_pivot->f->no); + } + else { + float cur[3]; + mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f)); + add_v3_v3(cn_wght, cur); + } + if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { + break; + } + lfan_pivot = lfan_pivot_next; + } + + normalize_v3(cn_wght); + mul_v3_fl(cn_wght, hn_strength); + float n_final[3]; + + while ((l = BLI_SMALLSTACK_POP(loops))) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + copy_v3_v3(n_final, l->f->no); + mul_v3_fl(n_final, 1.0f - hn_strength); + add_v3_v3(n_final, cn_wght); + normalize_v3(n_final); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors); + } + } + } + } while ((l_cur = l_cur->next) != l_first); + } +} + /* * This calls the new bevel code (added since 2.64) */ @@ -197,6 +303,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp, dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp, bmd->hnmode, NULL); + if (bmd->hnmode != MOD_BEVEL_HN_NONE) + bevel_mod_harden_normals(bmd, bm, bmd->hn_strength, bmd->hnmode, dvert, vgroup); + if(set_wn_strength) bevel_set_weighted_normal_face_strength(bm, md->scene); -- cgit v1.2.3 From e8a1b4d6452fc6ea3582f0f178f4da696c0e9c20 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Mon, 25 Jun 2018 13:47:46 +0530 Subject: Change bitmap to GHash in bevel_harden_normals_mode --- source/blender/bmesh/tools/bmesh_bevel.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index c63fe69762a..186d3a3c8e0 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -1665,32 +1665,33 @@ static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, B float n_final[3] = { 0.0f, 0.0f, 0.0f }; if (bp->hnmode == BEVEL_HN_FACE) { - BLI_bitmap *faces = BLI_BITMAP_NEW(bm->totface, __func__); + GHash *faceHash = BLI_ghash_int_new(__func__); + 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_BITMAP_TEST(faces, BM_elem_index_get(f_a))) { + if(f_a && !BLI_ghash_haskey(faceHash, 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_BITMAP_ENABLE(faces, BM_elem_index_get(f_a)); + BLI_ghash_insert(faceHash, SET_UINT_IN_POINTER(BM_elem_index_get(f_a)), NULL); } - if (f_b && !BLI_BITMAP_TEST(faces, BM_elem_index_get(f_b))) { + if(f_b && !BLI_ghash_haskey(faceHash, 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_BITMAP_ENABLE(faces, BM_elem_index_get(f_b)); + BLI_ghash_insert(faceHash, SET_UINT_IN_POINTER(BM_elem_index_get(f_b)), NULL); } } } - MEM_freeN(faces); + BLI_ghash_free(faceHash, NULL, NULL); normalize_v3(n_final); } else if (bp->hnmode == BEVEL_HN_ADJ) { -- cgit v1.2.3 From 3504b27c5074d49ed19f86c212c584f37a343d33 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Wed, 27 Jun 2018 20:19:15 +0530 Subject: Patch to fix shading continuity. Added it as extension to harden. Tried out different methods to fix normals, Though as with width and segments changes shape, orientation of new polys a non-smooth method of fix was not possible. Current method aggregates vertex normals into a smooth fan without affecting edge shading. Still need to fix the crease at new vertex edges --- source/blender/bmesh/intern/bmesh_operators.h | 1 + source/blender/bmesh/tools/bmesh_bevel.c | 102 ++++++++++++++++++++++++++ source/blender/makesdna/DNA_modifier_types.h | 1 + source/blender/makesrna/intern/rna_modifier.c | 1 + source/blender/modifiers/intern/MOD_bevel.c | 2 +- 5 files changed, 106 insertions(+), 1 deletion(-) diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h index 1b5694c3ee8..9f6ac50a3e5 100644 --- a/source/blender/bmesh/intern/bmesh_operators.h +++ b/source/blender/bmesh/intern/bmesh_operators.h @@ -131,6 +131,7 @@ enum { BEVEL_HN_NONE, BEVEL_HN_FACE, BEVEL_HN_ADJ, + BEVEL_HN_FIX_SHA, }; extern const BMOpDefine *bmo_opdefines[]; diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 186d3a3c8e0..132436c70f0 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -44,6 +44,7 @@ #include "BKE_customdata.h" #include "BKE_deform.h" +#include "BKE_mesh.h" #include "eigen_capi.h" @@ -1721,6 +1722,85 @@ static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, B } while (bcur != bstart); } +static void bevel_fix_normal_shading_continuity(BevelParams *bp, BMesh *bm, BevVert *bv, GHash *faceHash) +{ + VMesh *vm = bv->vmesh; + BoundVert *bcur = bv->vmesh->boundstart, *start = bcur; + int ns = vm->seg; + int ns2 = ns / 2; + int count = 0; + + BMFace *f; + BMLoop *l; + BMIter liter, fiter; + + int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + + if (BLI_ghash_haskey(faceHash, f)) { + BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], l->v->no, clnors); + } + } + } + + do { + for (int i = 0; i <= ns; i++) { + BMVert *v1 = mesh_vert(vm, bcur->index, 0, i)->v, *v2; + BMEdge *e; + BMIter eiter; + + BM_ITER_ELEM(e, &eiter, v1, BM_EDGES_OF_VERT) { + BMFace *f_a, *f_b; + BM_edge_face_pair(e, &f_a, &f_b); + + bool _f_a = false, _f_b = false; + if (f_a) + _f_a = BLI_ghash_haskey(faceHash, f_a); + if (f_b) + _f_b = BLI_ghash_haskey(faceHash, f_b); + if (_f_a ^ _f_b) { + + BM_ITER_ELEM(l, &liter, v1, BM_LOOPS_OF_VERT) { + + if (l->f == f_a || l->f == f_b) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + float res[3]; + copy_v3_v3(res, f_a->no); + add_v3_v3(res, f_b->no); + mul_v3_fl(res, 0.5f); + normalize_v3(res); + + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], res, clnors); + } + } + } + } + + float res_n[3]; + zero_v3(res_n); + BM_ITER_ELEM(l, &liter, v1, BM_LOOPS_OF_VERT) { + if (!BLI_ghash_haskey(faceHash, l->f)) { + add_v3_v3(res_n, l->f->no); + } + } + normalize_v3(res_n); + BM_ITER_ELEM(l, &liter, v1, BM_LOOPS_OF_VERT) { + if (BLI_ghash_haskey(faceHash, l->f)) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data(bm ->lnor_spacearr->lspacearr[l_index], res_n, clnors); + } + } + } + bcur = bcur->next; + } while (bcur != start); +} + /* Set the any_seam property for a BevVert and all its BoundVerts */ static void set_bound_vert_seams(BevVert *bv, bool mark_seam, bool mark_sharp) { @@ -5648,6 +5728,17 @@ void BM_mesh_bevel( } } + GHash *faceHash; + if (!bm->use_toolflags && bp.hnmode == BEVEL_HN_FIX_SHA) { + faceHash = BLI_ghash_ptr_new(__func__); + BMFace *f; + BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG)) { + BLI_ghash_insert(faceHash, f, NULL); + } + } + } + /* Build polygons for edges */ if (!bp.vertex_only) { BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { @@ -5664,6 +5755,7 @@ void BM_mesh_bevel( bevel_harden_normals_mode(bm, &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)) { @@ -5672,6 +5764,16 @@ void BM_mesh_bevel( } } + if (!bm->use_toolflags && bp.hnmode == BEVEL_HN_FIX_SHA) { + BM_mesh_normals_update(bm); + BM_lnorspace_update(bm); + GHASH_ITER(giter, bp.vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + if (!bm->use_toolflags) + bevel_fix_normal_shading_continuity(&bp, bm, bv, faceHash); + } + BLI_ghash_free(faceHash, NULL, NULL); + } BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 83f98c1181e..7ae9383a907 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -379,6 +379,7 @@ enum { MOD_BEVEL_HN_NONE, MOD_BEVEL_HN_FACE, MOD_BEVEL_HN_ADJ, + MOD_BEVEL_FIX_SHA, }; typedef struct SmokeModifierData { diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 497125476a2..87c28115325 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -3028,6 +3028,7 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) { MOD_BEVEL_HN_NONE, "HN_NONE", 0, "Off", "Do not use Harden Normals" }, { MOD_BEVEL_HN_FACE, "HN_FACE", 0, "Face Area", "Use faces as weight" }, { MOD_BEVEL_HN_ADJ, "HN_ADJ", 0, "Vertex average", "Use adjacent vertices as weight" }, + { MOD_BEVEL_FIX_SHA, "FIX_SHA", 0, "Fix shading", "Fix normal shading continuity" }, { 0, NULL, 0, NULL, NULL }, }; diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 77b306466c3..735436f3971 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -303,7 +303,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp, dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp, bmd->hnmode, NULL); - if (bmd->hnmode != MOD_BEVEL_HN_NONE) + if (bmd->hnmode != MOD_BEVEL_HN_NONE && bmd->hnmode != MOD_BEVEL_FIX_SHA) bevel_mod_harden_normals(bmd, bm, bmd->hn_strength, bmd->hnmode, dvert, vgroup); if(set_wn_strength) -- cgit v1.2.3 From 0c25881c391b84e238fa9503ec8c6a6fa0e2e439 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Sun, 29 Jul 2018 19:52:23 +0530 Subject: Cleanup of fix_normal_shading Fixed the edge crease that was present and also made significant performance improvements. --- source/blender/bmesh/tools/bmesh_bevel.c | 114 ++++++++++++++----------------- 1 file changed, 51 insertions(+), 63 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 132436c70f0..bf32e8e6970 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -185,6 +185,7 @@ typedef struct BevVert { EdgeHalf *edges; /* array of size edgecount; CCW order from vertex normal side */ BMEdge **wire_edges; /* array of size wirecount of wire edges */ VMesh *vmesh; /* mesh structure for replacing vertex */ + bool fix_shading; } BevVert; /* Bevel parameters and state */ @@ -192,6 +193,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 */ @@ -1722,34 +1725,23 @@ static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, B } while (bcur != bstart); } -static void bevel_fix_normal_shading_continuity(BevelParams *bp, BMesh *bm, BevVert *bv, GHash *faceHash) +static void bevel_fix_normal_shading_continuity(BevelParams *bp, BMesh *bm, BevVert *bv) { + GHash *faceHash = bp->faceHash; VMesh *vm = bv->vmesh; BoundVert *bcur = bv->vmesh->boundstart, *start = bcur; int ns = vm->seg; int ns2 = ns / 2; - int count = 0; - BMFace *f; BMLoop *l; - BMIter liter, fiter; + BMIter liter; int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); - - BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { - - if (BLI_ghash_haskey(faceHash, f)) { - BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) { - const int l_index = BM_elem_index_get(l); - short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], l->v->no, clnors); - } - } - } + float ref = 20.0f; do { for (int i = 0; i <= ns; i++) { - BMVert *v1 = mesh_vert(vm, bcur->index, 0, i)->v, *v2; + BMVert *v1 = mesh_vert(vm, bcur->index, 0, i)->v; BMEdge *e; BMIter eiter; @@ -1769,33 +1761,28 @@ static void bevel_fix_normal_shading_continuity(BevelParams *bp, BMesh *bm, BevV if (l->f == f_a || l->f == f_b) { const int l_index = BM_elem_index_get(l); short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - float res[3]; - copy_v3_v3(res, f_a->no); - add_v3_v3(res, f_b->no); - mul_v3_fl(res, 0.5f); - normalize_v3(res); + float n_final[3], pow_a[3], pow_b[3]; + + zero_v3(n_final); + copy_v3_v3(pow_a, f_a->no); + copy_v3_v3(pow_b, f_b->no); + if (_f_a) { + mul_v3_fl(pow_a, ns / ref); + mul_v3_fl(pow_b, ref / ns); + } + else { + mul_v3_fl(pow_b, ns / ref); + mul_v3_fl(pow_a, ref / ns); + } + add_v3_v3(n_final, pow_a); + add_v3_v3(n_final, pow_b); + normalize_v3(n_final); - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], res, clnors); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors); } } } } - - float res_n[3]; - zero_v3(res_n); - BM_ITER_ELEM(l, &liter, v1, BM_LOOPS_OF_VERT) { - if (!BLI_ghash_haskey(faceHash, l->f)) { - add_v3_v3(res_n, l->f->no); - } - } - normalize_v3(res_n); - BM_ITER_ELEM(l, &liter, v1, BM_LOOPS_OF_VERT) { - if (BLI_ghash_haskey(faceHash, l->f)) { - const int l_index = BM_elem_index_get(l); - short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - BKE_lnor_space_custom_normal_to_data(bm ->lnor_spacearr->lspacearr[l_index], res_n, clnors); - } - } } bcur = bcur->next; } while (bcur != start); @@ -3283,6 +3270,8 @@ static VMesh *adj_vmesh(BevelParams *bp, BevVert *bv) return tri_corner_adj_vmesh(bp, bv); } + bv->fix_shading = true; + /* First construct an initial control mesh, with nseg==2 */ ns = bv->vmesh->seg; vm0 = new_adj_vmesh(mem_arena, n, 2, bv->vmesh->boundstart); @@ -3726,7 +3715,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; @@ -3771,6 +3760,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) && bv->fix_shading); + /* copy final vmesh into bv->vmesh, make BMVerts and BMFaces */ vm = bv->vmesh; for (i = 0; i < n; i++) { @@ -3812,24 +3803,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); } } @@ -3838,25 +3829,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); @@ -5681,6 +5674,7 @@ void BM_mesh_bevel( 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 */ bp.pro_super_r = PRO_SQUARE_R; @@ -5718,6 +5712,11 @@ void BM_mesh_bevel( adjust_offsets(&bp); } + const bool do_fix_shading = (!bm->use_toolflags && bp.hnmode == BEVEL_HN_FIX_SHA); + if (do_fix_shading) { + bp.faceHash = BLI_ghash_ptr_new(__func__); + } + /* Build the meshes around vertices, now that positions are final */ /* Note: could use GHASH_ITER over bp.vert_hash when backward compatibility no longer matters */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { @@ -5728,17 +5727,6 @@ void BM_mesh_bevel( } } - GHash *faceHash; - if (!bm->use_toolflags && bp.hnmode == BEVEL_HN_FIX_SHA) { - faceHash = BLI_ghash_ptr_new(__func__); - BMFace *f; - BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_TAG)) { - BLI_ghash_insert(faceHash, f, NULL); - } - } - } - /* Build polygons for edges */ if (!bp.vertex_only) { BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { @@ -5764,15 +5752,15 @@ void BM_mesh_bevel( } } - if (!bm->use_toolflags && bp.hnmode == BEVEL_HN_FIX_SHA) { + if (do_fix_shading) { BM_mesh_normals_update(bm); BM_lnorspace_update(bm); GHASH_ITER(giter, bp.vert_hash) { bv = BLI_ghashIterator_getValue(&giter); - if (!bm->use_toolflags) - bevel_fix_normal_shading_continuity(&bp, bm, bv, faceHash); + if (bv->fix_shading) + bevel_fix_normal_shading_continuity(&bp, bm, bv); } - BLI_ghash_free(faceHash, NULL, NULL); + BLI_ghash_free(bp.faceHash, NULL, NULL); } BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { -- cgit v1.2.3 From 74ace41160bd6e98c904b34e5efe0893b1719387 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Mon, 2 Jul 2018 21:47:15 +0530 Subject: Minor cleanup and fixed normal updating erasing entire mesh --- source/blender/bmesh/tools/bmesh_bevel.c | 34 ++++++++++++++-------------- source/blender/editors/mesh/editmesh_bevel.c | 9 ++++---- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index bf32e8e6970..9259be7b240 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -37,7 +37,6 @@ #include "BLI_array.h" #include "BLI_alloca.h" -#include "BLI_bitmap.h" #include "BLI_gsqueue.h" #include "BLI_math.h" #include "BLI_memarena.h" @@ -1538,12 +1537,12 @@ static void check_edge_data_seam_sharp_edges(BevVert *bv, int flag, bool neg) { EdgeHalf *e = &bv->edges[0], *efirst = &bv->edges[0]; - while (neg ^ !EDGE_DATA_CHECK(e, flag)) { + while ((!neg && !EDGE_DATA_CHECK(e, flag) || (neg && EDGE_DATA_CHECK(e, flag)))) { e = e->next; if (e == efirst) break; } - if (neg ^ !EDGE_DATA_CHECK(e, flag)) + if ((!neg && !EDGE_DATA_CHECK(e, flag) || (neg && EDGE_DATA_CHECK(e, flag)))) return; efirst = e; @@ -1551,12 +1550,13 @@ static void check_edge_data_seam_sharp_edges(BevVert *bv, int flag, bool neg) int flag_count = 0; EdgeHalf *ne = e->next; - while ((neg ^ !EDGE_DATA_CHECK(ne, flag)) && ne != efirst) { + while ((!neg && !EDGE_DATA_CHECK(e, flag) || (neg && EDGE_DATA_CHECK(e, flag))) && ne != efirst) { if (ne->is_bev) flag_count++; ne = ne->next; } - if (ne == e || (ne == efirst && (neg ^ !EDGE_DATA_CHECK(efirst, flag)))) { + if (ne == e || (ne == efirst && (!neg && !EDGE_DATA_CHECK(e, flag) || + (neg && EDGE_DATA_CHECK(e, flag))))) { break; } if (flag == BM_ELEM_SEAM) @@ -5736,14 +5736,14 @@ void BM_mesh_bevel( } } - GHASH_ITER(giter, bp.vert_hash) { - bv = BLI_ghashIterator_getValue(&giter); - bevel_extend_edge_data(bv); - if(bm->use_toolflags) + if (bm->use_toolflags) { + GHASH_ITER(giter, bp.vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + bevel_extend_edge_data(bv); bevel_harden_normals_mode(bm, &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)) { @@ -5752,6 +5752,13 @@ void BM_mesh_bevel( } } + BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + BLI_assert(find_bevvert(&bp, v) != NULL); + BM_vert_kill(bm, v); + } + } + if (do_fix_shading) { BM_mesh_normals_update(bm); BM_lnorspace_update(bm); @@ -5763,13 +5770,6 @@ void BM_mesh_bevel( BLI_ghash_free(bp.faceHash, NULL, NULL); } - BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - BLI_assert(find_bevvert(&bp, v) != NULL); - BM_vert_kill(bm, v); - } - } - /* When called from operator (as opposed to modifier), bm->use_toolflags * will be set, and we to transfer the oflags to BM_ELEM_TAGs */ if (bm->use_toolflags) { diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 40be91aada1..d92d655641f 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -197,8 +197,8 @@ static void bevel_harden_normals(BMEditMesh *em, BMOperator *bmop, float face_st normalize_v3(cn_wght); normalize_v3(cn_unwght); if (calc_n) { - mul_v3_fl(calc_n, face_strength); - mul_v3_fl(cn_wght, 1.0f - face_strength); + mul_v3_fl(cn_wght, face_strength); + mul_v3_fl(calc_n, 1.0f - face_strength); add_v3_v3(calc_n, cn_wght); normalize_v3(calc_n); } @@ -341,7 +341,8 @@ static bool edbm_bevel_calc(wmOperator *op) BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); } - bevel_harden_normals(em, &bmop, strength, hnmode); + if(hnmode != BEVEL_HN_NONE) + bevel_harden_normals(em, &bmop, strength, hnmode); /* no need to de-select existing geometry */ if (!EDBM_op_finish(em, &bmop, op, true)) { @@ -788,5 +789,5 @@ void MESH_OT_bevel(wmOperatorType *ot) RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100); RNA_def_float(ot->srna, "strength", 0.5f, 0.0f, 1.0f, "Normal Strength", "Strength of calculated normal", 0.0f, 1.0f); - RNA_def_enum(ot->srna, "hnmode", harden_normals_items, BEVEL_HN_FACE, "Normal Mode", "Weighting mode for Harden Normals"); + RNA_def_enum(ot->srna, "hnmode", harden_normals_items, BEVEL_HN_NONE, "Normal Mode", "Weighting mode for Harden Normals"); } -- cgit v1.2.3 From 368a64fe041ee0950584f5b51e2f64036edb31d0 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Mon, 2 Jul 2018 22:55:33 +0530 Subject: Refactored bevel normal editing functionality. --- source/blender/bmesh/tools/bmesh_bevel.c | 39 ++++++++-------- source/blender/bmesh/tools/bmesh_bevel.h | 2 +- source/blender/makesdna/DNA_modifier_types.h | 6 +++ source/blender/modifiers/intern/MOD_bevel.c | 69 ++++++++++++++++++++++++++-- 4 files changed, 91 insertions(+), 25 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 9259be7b240..789c2ae4c63 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" @@ -5650,7 +5651,7 @@ void BM_mesh_bevel( 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 mark_seam, const bool mark_sharp, - const int hnmode, BMOperator *op) + const int hnmode, void *mod_bmop_customdata) { BMIter iter; BMVert *v, *v_next; @@ -5659,6 +5660,9 @@ void BM_mesh_bevel( BevelParams bp = {NULL}; GHashIterator giter; + BMOperator *op; + BevelModNorEditData *clnordata; + bp.offset = offset; bp.offset_type = offset_type; bp.seg = segments; @@ -5687,6 +5691,14 @@ void BM_mesh_bevel( BLI_memarena_use_calloc(bp.mem_arena); set_profile_spacing(&bp); + 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)) { @@ -5712,11 +5724,6 @@ void BM_mesh_bevel( adjust_offsets(&bp); } - const bool do_fix_shading = (!bm->use_toolflags && bp.hnmode == BEVEL_HN_FIX_SHA); - if (do_fix_shading) { - bp.faceHash = BLI_ghash_ptr_new(__func__); - } - /* Build the meshes around vertices, now that positions are final */ /* Note: could use GHASH_ITER over bp.vert_hash when backward compatibility no longer matters */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { @@ -5736,10 +5743,11 @@ void BM_mesh_bevel( } } - if (bm->use_toolflags) { - GHASH_ITER(giter, bp.vert_hash) { - bv = BLI_ghashIterator_getValue(&giter); - bevel_extend_edge_data(bv); + /* 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(bm, &bp, bv, op); } } @@ -5759,17 +5767,6 @@ void BM_mesh_bevel( } } - if (do_fix_shading) { - BM_mesh_normals_update(bm); - BM_lnorspace_update(bm); - GHASH_ITER(giter, bp.vert_hash) { - bv = BLI_ghashIterator_getValue(&giter); - if (bv->fix_shading) - bevel_fix_normal_shading_continuity(&bp, bm, bv); - } - BLI_ghash_free(bp.faceHash, NULL, NULL); - } - /* When called from operator (as opposed to modifier), bm->use_toolflags * will be set, and we to transfer the oflags to BM_ELEM_TAGs */ if (bm->use_toolflags) { diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h index f43289aac27..5cf8b1e78bb 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.h +++ b/source/blender/bmesh/tools/bmesh_bevel.h @@ -34,6 +34,6 @@ void BM_mesh_bevel( 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 mark_seam, const bool mark_sharp, - const int hnmode, BMOperator *op); + const int hnmode, void *mod_bmop_customdata); #endif /* __BMESH_BEVEL_H__ */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 7ae9383a907..33381be0ef5 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -318,6 +318,11 @@ enum { MOD_EDGESPLIT_FROMFLAG = (1 << 2), }; +typedef struct BevelModNorEditData { + struct GHash *faceHash; + struct GHash *vert_hash; +} BevelModNorEditData; + typedef struct BevelModifierData { ModifierData modifier; @@ -337,6 +342,7 @@ typedef struct BevelModifierData { int hnmode; float hn_strength; char defgrp_name[64]; + struct BevelModNorEditData clnordata; } BevelModifierData; /* BevelModifierData->flags and BevelModifierData->lim_flags */ diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 735436f3971..b30d6c2e669 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -140,6 +140,7 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn e_next = lfan_pivot->e; BLI_SMALLSTACK_DECLARE(loops, BMLoop *); float cn_wght[3] = { 0.0f, 0.0f, 0.0f }; + bool normal_to_recon_face = false; while (true) { lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); @@ -208,6 +209,62 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn } } +static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *bm) +{ + BM_mesh_normals_update(bm); + BM_lnorspace_update(bm); + + GHash *faceHash = bmd->clnordata.faceHash; + BMEdge *e; + BMLoop *l; + BMIter liter, eiter; + + int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + float ref = 10.0f; + + BM_ITER_MESH(e, &eiter, bm, BM_EDGES_OF_MESH) { + BMFace *f_a, *f_b; + BM_edge_face_pair(e, &f_a, &f_b); + + bool _f_a = false, _f_b = false; + if (f_a) + _f_a = BLI_ghash_haskey(faceHash, f_a); + if (f_b) + _f_b = BLI_ghash_haskey(faceHash, f_b); + if (_f_a ^ _f_b) { + + for (int i = 0; i < 2; i++) { + BMVert *v = (i == 0) ? e->v1 : e->v2; + BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) { + + if (l->f == f_a || l->f == f_b) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + float n_final[3], pow_a[3], pow_b[3]; + + zero_v3(n_final); + copy_v3_v3(pow_a, f_a->no); + copy_v3_v3(pow_b, f_b->no); + if (_f_a) { + mul_v3_fl(pow_a, bmd->res / ref); + mul_v3_fl(pow_b, ref / bmd->res); + } + else { + mul_v3_fl(pow_b, bmd->res / ref); + mul_v3_fl(pow_a, ref / bmd->res); + } + add_v3_v3(n_final, pow_a); + add_v3_v3(n_final, pow_b); + normalize_v3(n_final); + + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors); + } + } + } + } + } +} + /* * This calls the new bevel code (added since 2.64) */ @@ -301,10 +358,14 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes BM_mesh_bevel(bm, bmd->value, offset_type, bmd->res, bmd->profile, vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp, - dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp, bmd->hnmode, NULL); + dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp, bmd->hnmode, &bmd->clnordata); - if (bmd->hnmode != MOD_BEVEL_HN_NONE && bmd->hnmode != MOD_BEVEL_FIX_SHA) - bevel_mod_harden_normals(bmd, bm, bmd->hn_strength, bmd->hnmode, dvert, vgroup); + if (bmd->hnmode != MOD_BEVEL_HN_NONE) { + if (bmd->hnmode != BEVEL_HN_FIX_SHA) + bevel_mod_harden_normals(bmd, bm, bmd->hn_strength, bmd->hnmode, dvert, vgroup); + else + bevel_fix_normal_shading_continuity(bmd, bm); + } if(set_wn_strength) bevel_set_weighted_normal_face_strength(bm, md->scene); @@ -316,6 +377,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes bm->ftoolflagpool == NULL); /* make sure we never alloc'd these */ BM_mesh_free(bm); + BLI_ghash_free(bmd->clnordata.faceHash, NULL, NULL); + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; return result; -- cgit v1.2.3 From 190d1b2f7ae04cbe244b581f78dfdeb3387c9ea0 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Tue, 3 Jul 2018 19:01:20 +0530 Subject: Fixed merge errors --- source/blender/editors/mesh/editmesh_tools.c | 8 ++++---- source/blender/editors/transform/transform.c | 2 +- source/blender/modifiers/intern/MOD_bevel.c | 11 ++++++++--- source/blender/modifiers/intern/MOD_weighted_normal.c | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index f8c1db30276..9683bf43968 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -7049,7 +7049,7 @@ static void point_normals_free(bContext *C, wmOperator *op) BMLoopNorEditDataArray *lnors_ed_arr = op->customdata; BM_loop_normal_editdata_array_free(lnors_ed_arr); op->customdata = NULL; - ED_area_headerprint(CTX_wm_area(C), NULL); + ED_area_status_text(CTX_wm_area(C), NULL); } static void point_normals_update_header(bContext *C, wmOperator *op) @@ -7080,7 +7080,7 @@ static void point_normals_update_header(bContext *C, wmOperator *op) #undef WM_MODALKEY - ED_area_headerprint(CTX_wm_area(C), header); + ED_area_status_text(CTX_wm_area(C), header); } /* TODO move that to generic function in BMesh? */ @@ -7226,7 +7226,7 @@ static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent * case EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR: new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; - ED_view3d_cursor3d_update(C, event->mval); + ED_view3d_cursor3d_update(C, event->mval, false, V3D_CURSOR_ORIENT_NONE); copy_v3_v3(target, ED_view3d_cursor3d_get(scene, v3d)->location); break; @@ -8263,4 +8263,4 @@ void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot) ot->prop = RNA_def_boolean(ot->srna, "set", 0, "Set value", "Set Value of faces"); RNA_def_property_flag(ot->prop, PROP_HIDDEN); -} \ No newline at end of file +} diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index ba9430c46f7..9a52127b201 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -4428,7 +4428,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2])) recalcData(t); - ED_area_headerprint(t->sa, str); + ED_area_status_text(t->sa, str); } /** \} */ diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index aa12093b505..67634dba170 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -53,6 +53,8 @@ #include "bmesh.h" #include "bmesh_tools.h" +#include "DEG_depsgraph_query.h" + static void initData(ModifierData *md) { BevelModifierData *bmd = (BevelModifierData *) md; @@ -289,6 +291,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes const bool mark_sharp = (bmd->edge_flags & MOD_BEVEL_MARK_SHARP); const bool set_wn_strength = (bmd->flags & MOD_BEVEL_SET_WN_STR); + struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + bm = BKE_mesh_to_bmesh_ex( mesh, &(struct BMeshCreateParams){0}, @@ -363,12 +367,12 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes if (bmd->hnmode != MOD_BEVEL_HN_NONE) { if (bmd->hnmode != BEVEL_HN_FIX_SHA) bevel_mod_harden_normals(bmd, bm, bmd->hn_strength, bmd->hnmode, dvert, vgroup); - else + else if(bmd->clnordata.faceHash) bevel_fix_normal_shading_continuity(bmd, bm); } if(set_wn_strength) - bevel_set_weighted_normal_face_strength(bm, md->scene); + bevel_set_weighted_normal_face_strength(bm, scene); result = BKE_bmesh_to_mesh_nomain(bm, &(struct BMeshToMeshParams){0}); @@ -377,7 +381,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes bm->ftoolflagpool == NULL); /* make sure we never alloc'd these */ BM_mesh_free(bm); - BLI_ghash_free(bmd->clnordata.faceHash, NULL, NULL); + if(bmd->clnordata.faceHash) + BLI_ghash_free(bmd->clnordata.faceHash, NULL, NULL); result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index b43ef698cc4..a2ace1aadc4 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -554,7 +554,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes MDeformVert *dvert; int defgrp_index; - modifier_get_vgroup_mesh(ob, result, wnmd->defgrp_name, &dvert, &defgrp_index); + MOD_get_vgroup(ctx->object, mesh, wnmd->defgrp_name, &dvert, &defgrp_index); WeightedNormalData wn_data = { .numVerts = numVerts, -- cgit v1.2.3 From 1c699d75a03c76ac6922906e8b13e6dc53d8075a Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Tue, 3 Jul 2018 21:51:01 +0530 Subject: Fixed bugs in normal shading continuity and added support to have corner vertices of a vmesh to have same normal as reconstructed face in harden --- source/blender/modifiers/intern/MOD_bevel.c | 56 ++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 67634dba170..f89494f7c71 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -111,15 +111,18 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn { if (bmd->res > 20) return; + BM_mesh_normals_update(bm); BM_lnorspace_update(bm); BM_normals_loops_edges_tag(bm, true); + const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0; int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); BMFace *f; BMLoop *l, *l_cur, *l_first; BMIter fiter; + GHash *faceHash = bmd->clnordata.faceHash; BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { l_cur = l_first = BM_FACE_FIRST_LOOP(f); @@ -142,7 +145,8 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn e_next = lfan_pivot->e; BLI_SMALLSTACK_DECLARE(loops, BMLoop *); float cn_wght[3] = { 0.0f, 0.0f, 0.0f }; - bool normal_to_recon_face = false; + int recon_face_count = 0; /* Reconstructed face */ + BMFace *recon_face; while (true) { lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); @@ -190,6 +194,10 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn break; } lfan_pivot = lfan_pivot_next; + if (!BLI_ghash_haskey(faceHash, f)) { + recon_face = f; + recon_face_count++; + } } normalize_v3(cn_wght); @@ -199,11 +207,19 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn while ((l = BLI_SMALLSTACK_POP(loops))) { const int l_index = BM_elem_index_get(l); short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - copy_v3_v3(n_final, l->f->no); - mul_v3_fl(n_final, 1.0f - hn_strength); - add_v3_v3(n_final, cn_wght); - normalize_v3(n_final); - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors); + + if (!vertex_only || !recon_face_count) { + copy_v3_v3(n_final, l->f->no); + mul_v3_fl(n_final, 1.0f - hn_strength); + add_v3_v3(n_final, cn_wght); + normalize_v3(n_final); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors); + } + else if (recon_face_count == 1) { + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], recon_face->no, clnors); + } + else if(BLI_ghash_haskey(faceHash, l->f)) + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], l->v->no, clnors); } } } @@ -222,6 +238,7 @@ static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *b BMIter liter, eiter; int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + const float hn_strength = bmd->hn_strength; float ref = 10.0f; BM_ITER_MESH(e, &eiter, bm, BM_EDGES_OF_MESH) { @@ -264,6 +281,29 @@ static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *b } } } + else if(_f_a == true && _f_b == true) { + for (int i = 0; i < 2; i++) { + BMVert *v = (i == 0) ? e->v1 : e->v2; + BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) { + + if(l->f == f_a || l->f == f_b) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + float n_final[3], cn_wght[3]; + + copy_v3_v3(n_final, v->no); + mul_v3_fl(n_final, hn_strength); + + copy_v3_v3(cn_wght, l->f->no); + mul_v3_fl(cn_wght, 1.0f - hn_strength); + + add_v3_v3(n_final, cn_wght); + normalize_v3(n_final); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors); + } + } + } + } } } @@ -364,10 +404,10 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp, dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp, bmd->hnmode, &bmd->clnordata); - if (bmd->hnmode != MOD_BEVEL_HN_NONE) { + if (bmd->value > 0 && bmd->hnmode != MOD_BEVEL_HN_NONE) { if (bmd->hnmode != BEVEL_HN_FIX_SHA) bevel_mod_harden_normals(bmd, bm, bmd->hn_strength, bmd->hnmode, dvert, vgroup); - else if(bmd->clnordata.faceHash) + else if(bmd->clnordata.faceHash && !vertex_only) bevel_fix_normal_shading_continuity(bmd, bm); } -- cgit v1.2.3 From b360c9d7f9d1fbb85b6cb71109da39731e3870c6 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Wed, 4 Jul 2018 00:04:03 +0530 Subject: cleanup of extend edge data and fixed minor errors --- source/blender/bmesh/tools/bmesh_bevel.c | 73 +++-------------------------- source/blender/modifiers/intern/MOD_bevel.c | 8 ++-- 2 files changed, 10 insertions(+), 71 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 789c2ae4c63..0a8ff3546be 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -1551,13 +1551,13 @@ static void check_edge_data_seam_sharp_edges(BevVert *bv, int flag, bool neg) int flag_count = 0; EdgeHalf *ne = e->next; - while ((!neg && !EDGE_DATA_CHECK(e, flag) || (neg && EDGE_DATA_CHECK(e, flag))) && ne != efirst) { + while ((!neg && !EDGE_DATA_CHECK(ne, flag) || (neg && EDGE_DATA_CHECK(ne, flag))) && ne != efirst) { if (ne->is_bev) flag_count++; ne = ne->next; } - if (ne == e || (ne == efirst && (!neg && !EDGE_DATA_CHECK(e, flag) || - (neg && EDGE_DATA_CHECK(e, flag))))) { + if (ne == e || (ne == efirst && (!neg && !EDGE_DATA_CHECK(efirst, flag) || + (neg && EDGE_DATA_CHECK(efirst, flag))))) { break; } if (flag == BM_ELEM_SEAM) @@ -1657,6 +1657,8 @@ static void bevel_extend_edge_data(BevVert *bv) static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, BMOperator *op) { + if (bp->hnmode == BEVEL_HN_NONE) + return; int mode = 1; VMesh *vm = bv->vmesh; @@ -1726,69 +1728,6 @@ static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, B } while (bcur != bstart); } -static void bevel_fix_normal_shading_continuity(BevelParams *bp, BMesh *bm, BevVert *bv) -{ - GHash *faceHash = bp->faceHash; - VMesh *vm = bv->vmesh; - BoundVert *bcur = bv->vmesh->boundstart, *start = bcur; - int ns = vm->seg; - int ns2 = ns / 2; - - BMLoop *l; - BMIter liter; - - int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); - float ref = 20.0f; - - do { - for (int i = 0; i <= ns; i++) { - BMVert *v1 = mesh_vert(vm, bcur->index, 0, i)->v; - BMEdge *e; - BMIter eiter; - - BM_ITER_ELEM(e, &eiter, v1, BM_EDGES_OF_VERT) { - BMFace *f_a, *f_b; - BM_edge_face_pair(e, &f_a, &f_b); - - bool _f_a = false, _f_b = false; - if (f_a) - _f_a = BLI_ghash_haskey(faceHash, f_a); - if (f_b) - _f_b = BLI_ghash_haskey(faceHash, f_b); - if (_f_a ^ _f_b) { - - BM_ITER_ELEM(l, &liter, v1, BM_LOOPS_OF_VERT) { - - if (l->f == f_a || l->f == f_b) { - const int l_index = BM_elem_index_get(l); - short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - float n_final[3], pow_a[3], pow_b[3]; - - zero_v3(n_final); - copy_v3_v3(pow_a, f_a->no); - copy_v3_v3(pow_b, f_b->no); - if (_f_a) { - mul_v3_fl(pow_a, ns / ref); - mul_v3_fl(pow_b, ref / ns); - } - else { - mul_v3_fl(pow_b, ns / ref); - mul_v3_fl(pow_a, ref / ns); - } - add_v3_v3(n_final, pow_a); - add_v3_v3(n_final, pow_b); - normalize_v3(n_final); - - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors); - } - } - } - } - } - bcur = bcur->next; - } while (bcur != start); -} - /* Set the any_seam property for a BevVert and all its BoundVerts */ static void set_bound_vert_seams(BevVert *bv, bool mark_seam, bool mark_sharp) { @@ -3761,7 +3700,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv) vm1 = adj_vmesh(bp, bv); } - bool do_fix_shading_bv = ((bp->faceHash != NULL) && bv->fix_shading); + bool do_fix_shading_bv = bp->faceHash != NULL; /* copy final vmesh into bv->vmesh, make BMVerts and BMFaces */ vm = bv->vmesh; diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index f89494f7c71..a61705646e6 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -190,14 +190,14 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f)); add_v3_v3(cn_wght, cur); } - if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { - break; - } - lfan_pivot = lfan_pivot_next; if (!BLI_ghash_haskey(faceHash, f)) { recon_face = f; recon_face_count++; } + if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { + break; + } + lfan_pivot = lfan_pivot_next; } normalize_v3(cn_wght); -- cgit v1.2.3 From 13741792abdaa2ea4f65d26988d40cb9483f0450 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Mon, 9 Jul 2018 21:55:08 +0530 Subject: Fixed artifacts in bevel with high profile and segments --- source/blender/bmesh/tools/bmesh_bevel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 0a8ff3546be..694581bfab2 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -5619,7 +5619,7 @@ void BM_mesh_bevel( 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; } -- cgit v1.2.3 From 962f89d487da41107d7d1b1ccf7e720767359cd0 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Tue, 10 Jul 2018 22:21:28 +0530 Subject: Changed default strength in harden --- source/blender/makesrna/intern/rna_modifier.c | 1 + source/blender/modifiers/intern/MOD_bevel.c | 1 + 2 files changed, 2 insertions(+) diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index c1b271e9214..70bd685dc56 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -3125,6 +3125,7 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "hn_strength", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, 0, 1); RNA_def_property_ui_range(prop, 0, 1, 1, 2); RNA_def_property_ui_text(prop, "Normal Strength", "Strength of calculated normal"); diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index a61705646e6..3418922e812 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -70,6 +70,7 @@ static void initData(ModifierData *md) bmd->profile = 0.5f; bmd->bevel_angle = DEG2RADF(30.0f); bmd->defgrp_name[0] = '\0'; + bmd->hn_strength = 0.5f; } static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) -- cgit v1.2.3 From 75149b429f1567e3358750a62eadeb1c32fef032 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Wed, 11 Jul 2018 22:36:44 +0530 Subject: Added support for beveling curves --- source/blender/modifiers/intern/MOD_bevel.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 3418922e812..f19443f2d5c 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -442,8 +442,9 @@ ModifierTypeInfo modifierType_Bevel = { /* type */ eModifierTypeType_Constructive, /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode, - + eModifierTypeFlag_EnableInEditmode | + eModifierTypeFlag_AcceptsCVs, + /* copyData */ modifier_copyData_generic, /* deformVerts_DM */ NULL, -- cgit v1.2.3 From 10c1f3fbfeadf009bac8b7f145ae6d55be0f30be Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Thu, 12 Jul 2018 23:30:29 +0530 Subject: Fixed shading errors with normals and added proper weighting to harden normals to make it consistent with wn modifier --- source/blender/bmesh/tools/bmesh_bevel.c | 37 ++++++++++++++++++++++++----- source/blender/modifiers/intern/MOD_bevel.c | 14 +++++++---- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 694581bfab2..c8a82eac743 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -3862,6 +3862,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)) { @@ -3907,6 +3909,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; @@ -3921,6 +3925,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); @@ -3929,6 +3934,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; @@ -3949,6 +3959,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); } } } @@ -3957,6 +3969,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); @@ -3968,6 +3981,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); @@ -3986,6 +4004,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--; } @@ -4962,13 +4983,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; @@ -5024,18 +5047,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); } @@ -5043,13 +5066,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]; } diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index f19443f2d5c..06c4f8c57fd 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -119,6 +119,7 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0; int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + bool do_normal_to_recon = (hn_strength == 1.0f); BMFace *f; BMLoop *l, *l_cur, *l_first; @@ -126,6 +127,9 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn GHash *faceHash = bmd->clnordata.faceHash; BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + if (!BLI_ghash_haskey(faceHash, f)) { + BM_elem_flag_set(f, BM_ELEM_HIDDEN, true); + } l_cur = l_first = BM_FACE_FIRST_LOOP(f); do { if ((!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) || (!BM_elem_flag_test(l_cur, BM_ELEM_TAG) && @@ -191,7 +195,7 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f)); add_v3_v3(cn_wght, cur); } - if (!BLI_ghash_haskey(faceHash, f)) { + if (!BLI_ghash_haskey(faceHash, lfan_pivot->f)) { recon_face = f; recon_face_count++; } @@ -209,16 +213,16 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn const int l_index = BM_elem_index_get(l); short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - if (!vertex_only || !recon_face_count) { + if (recon_face_count == 1 || do_normal_to_recon) { + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], recon_face->no, clnors); + } + else if (vertex_only == false || recon_face_count == 0) { copy_v3_v3(n_final, l->f->no); mul_v3_fl(n_final, 1.0f - hn_strength); add_v3_v3(n_final, cn_wght); normalize_v3(n_final); BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors); } - else if (recon_face_count == 1) { - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], recon_face->no, clnors); - } else if(BLI_ghash_haskey(faceHash, l->f)) BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], l->v->no, clnors); } -- cgit v1.2.3 From 43ac0f38d72a33cf6721909f3f671ac2dac6ffe3 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Tue, 17 Jul 2018 18:57:22 +0530 Subject: Fix weld incoherent normals with weld operation --- source/blender/bmesh/tools/bmesh_bevel.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index c8a82eac743..8a72ffc775f 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -4069,6 +4069,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 -- cgit v1.2.3 From b6b185691f018f6b175ffb58c65418991cda75f2 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Thu, 19 Jul 2018 19:27:45 +0530 Subject: Code cleanup and fixes --- source/blender/bmesh/tools/bmesh_bevel.c | 44 ++++++++++++++-------------- source/blender/editors/mesh/editmesh_bevel.c | 10 ++++--- source/blender/makesdna/DNA_modifier_types.h | 1 - source/blender/modifiers/intern/MOD_bevel.c | 40 ++++++++++++------------- 4 files changed, 48 insertions(+), 47 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 8a72ffc775f..bcf44ad4384 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -152,7 +152,7 @@ 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 add_seam; + int seam_len; int sharp_len; // int _pad; } BoundVert; @@ -1532,18 +1532,18 @@ static void snap_to_superellipsoid(float co[3], const float super_r, bool midlin co[2] = z; } -#define EDGE_DATA_CHECK(eh, flag) (BM_elem_flag_test(eh->e, flag)) +#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]; - while ((!neg && !EDGE_DATA_CHECK(e, flag) || (neg && EDGE_DATA_CHECK(e, flag)))) { + 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 ((!neg && !EDGE_DATA_CHECK(e, flag) || (neg && EDGE_DATA_CHECK(e, flag)))) + if ((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(e, flag) || (neg && BEV_EXTEND_EDGE_DATA_CHECK(e, flag)))) return; efirst = e; @@ -1551,17 +1551,17 @@ static void check_edge_data_seam_sharp_edges(BevVert *bv, int flag, bool neg) int flag_count = 0; EdgeHalf *ne = e->next; - while ((!neg && !EDGE_DATA_CHECK(ne, flag) || (neg && EDGE_DATA_CHECK(ne, flag))) && ne != efirst) { + 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 && !EDGE_DATA_CHECK(efirst, flag) || - (neg && EDGE_DATA_CHECK(efirst, flag))))) { + if (ne == e || (ne == efirst && (!neg && !BEV_EXTEND_EDGE_DATA_CHECK(efirst, flag) || + (neg && BEV_EXTEND_EDGE_DATA_CHECK(efirst, flag))))) { break; } if (flag == BM_ELEM_SEAM) - e->rightv->add_seam = flag_count; + e->rightv->seam_len = flag_count; else if (flag == BM_ELEM_SMOOTH) e->rightv->sharp_len = flag_count; e = ne; @@ -1576,11 +1576,11 @@ static void bevel_extend_edge_data(BevVert *bv) BoundVert *bcur = bv->vmesh->boundstart, *start = bcur; do { - if (bcur->add_seam) { - if (!bv->vmesh->boundstart->add_seam && start == bv->vmesh->boundstart) + if (bcur->seam_len) { + if (!bv->vmesh->boundstart->seam_len && start == bv->vmesh->boundstart) start = bcur; - int idxlen = bcur->index + bcur->add_seam; + 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; @@ -1659,7 +1659,6 @@ static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, B { if (bp->hnmode == BEVEL_HN_NONE) return; - int mode = 1; VMesh *vm = bv->vmesh; BoundVert *bcur = vm->boundstart, *bstart = bcur; @@ -1672,7 +1671,7 @@ static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, B float n_final[3] = { 0.0f, 0.0f, 0.0f }; if (bp->hnmode == BEVEL_HN_FACE) { - GHash *faceHash = BLI_ghash_int_new(__func__); + GHash *tempfaceHash = BLI_ghash_int_new(__func__); BM_ITER_ELEM(e, &eiter, bv->v, BM_EDGES_OF_VERT) { if (BM_elem_flag_test(e, BM_ELEM_TAG)) { @@ -1680,25 +1679,25 @@ static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, B BMFace *f_a, *f_b; BM_edge_face_pair(e, &f_a, &f_b); - if(f_a && !BLI_ghash_haskey(faceHash, SET_UINT_IN_POINTER(BM_elem_index_get(f_a)))) { + 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(faceHash, SET_UINT_IN_POINTER(BM_elem_index_get(f_a)), NULL); + BLI_ghash_insert(tempfaceHash, SET_UINT_IN_POINTER(BM_elem_index_get(f_a)), NULL); } - if(f_b && !BLI_ghash_haskey(faceHash, SET_UINT_IN_POINTER(BM_elem_index_get(f_b)))) { + 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(faceHash, SET_UINT_IN_POINTER(BM_elem_index_get(f_b)), NULL); + BLI_ghash_insert(tempfaceHash, SET_UINT_IN_POINTER(BM_elem_index_get(f_b)), NULL); } } } - BLI_ghash_free(faceHash, NULL, NULL); + BLI_ghash_free(tempfaceHash, NULL, NULL); normalize_v3(n_final); } else if (bp->hnmode == BEVEL_HN_ADJ) { @@ -1718,11 +1717,11 @@ static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, B do { if (BMO_slot_map_contains(nslot, bcur->nv.v) != true) { - float(*custom_normal) = MEM_callocN(sizeof(*custom_normal) * 3, __func__); - add_v3_v3(custom_normal, n_final); - normalize_v3(custom_normal); + 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, custom_normal); + BMO_slot_map_insert(op, nslot, bcur->nv.v, vert_normal); } bcur = bcur->next; } while (bcur != bstart); @@ -5662,6 +5661,7 @@ 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 { diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index f6b69beac71..83da84357dc 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -140,7 +140,7 @@ static void bevel_harden_normals(BMEditMesh *em, BMOperator *bmop, float face_st { BKE_editmesh_lnorspace_update(em); BM_normals_loops_edges_tag(em->bm, true); - int cd_clnors_offset = CustomData_get_offset(&em->bm->ldata, CD_CUSTOMLOOPNORMAL); + const int cd_clnors_offset = CustomData_get_offset(&em->bm->ldata, CD_CUSTOMLOOPNORMAL); BMesh *bm = em->bm; BMFace *f; @@ -181,10 +181,12 @@ static void bevel_harden_normals(BMEditMesh *em, BMOperator *bmop, float face_st else { e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e; } + BLI_SMALLSTACK_PUSH(loops, lfan_pivot); float cur[3]; mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f)); add_v3_v3(cn_wght, cur); + if(BM_elem_flag_test(lfan_pivot->f, BM_ELEM_SELECT)) add_v3_v3(cn_unwght, cur); @@ -310,7 +312,7 @@ static bool edbm_bevel_calc(wmOperator *op) const bool loop_slide = RNA_boolean_get(op->ptr, "loop_slide"); const bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam"); const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); - const float strength = RNA_float_get(op->ptr, "strength"); + const float hn_strength = RNA_float_get(op->ptr, "strength"); const int hnmode = RNA_enum_get(op->ptr, "hnmode"); @@ -330,7 +332,7 @@ static bool edbm_bevel_calc(wmOperator *op) "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b " "material=%i loop_slide=%b mark_seam=%b mark_sharp=%b strength=%f hnmode=%i", BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, - clamp_overlap, material, loop_slide, mark_seam, mark_sharp, strength, hnmode); + clamp_overlap, material, loop_slide, mark_seam, mark_sharp, hn_strength, hnmode); BMO_op_exec(em->bm, &bmop); @@ -342,7 +344,7 @@ static bool edbm_bevel_calc(wmOperator *op) } if(hnmode != BEVEL_HN_NONE) - bevel_harden_normals(em, &bmop, strength, hnmode); + bevel_harden_normals(em, &bmop, hn_strength, hnmode); /* no need to de-select existing geometry */ if (!EDBM_op_finish(em, &bmop, op, true)) { diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 5e8ead09d91..fec73c267ce 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -318,7 +318,6 @@ enum { typedef struct BevelModNorEditData { struct GHash *faceHash; - struct GHash *vert_hash; } BevelModNorEditData; typedef struct BevelModifierData { diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 06c4f8c57fd..1ada8b215c5 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -108,9 +108,9 @@ static void bevel_set_weighted_normal_face_strength(BMesh *bm, Scene *scene) } } -static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn_strength, int hnmode, MDeformVert *dvert, int vgroup) +static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, const float hn_strength, const int hnmode, MDeformVert *dvert, int vgroup) { - if (bmd->res > 20) + if (bmd->res > 20 || bmd->value == 0) return; BM_mesh_normals_update(bm); @@ -118,8 +118,8 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn BM_normals_loops_edges_tag(bm, true); const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0; - int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); - bool do_normal_to_recon = (hn_strength == 1.0f); + const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + const bool do_normal_to_recon = (hn_strength == 1.0f); BMFace *f; BMLoop *l, *l_cur, *l_first; @@ -127,9 +127,7 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn GHash *faceHash = bmd->clnordata.faceHash; BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BLI_ghash_haskey(faceHash, f)) { - BM_elem_flag_set(f, BM_ELEM_HIDDEN, true); - } + l_cur = l_first = BM_FACE_FIRST_LOOP(f); do { if ((!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) || (!BM_elem_flag_test(l_cur, BM_ELEM_TAG) && @@ -234,6 +232,10 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, float hn static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *bm) { + const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0; + if (bmd->value == 0 || bmd->clnordata.faceHash == NULL && vertex_only) + return; + BM_mesh_normals_update(bm); BM_lnorspace_update(bm); @@ -242,7 +244,7 @@ static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *b BMLoop *l; BMIter liter, eiter; - int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); const float hn_strength = bmd->hn_strength; float ref = 10.0f; @@ -250,12 +252,12 @@ static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *b BMFace *f_a, *f_b; BM_edge_face_pair(e, &f_a, &f_b); - bool _f_a = false, _f_b = false; + bool has_f_a = false, has_f_b = false; if (f_a) - _f_a = BLI_ghash_haskey(faceHash, f_a); + has_f_a = BLI_ghash_haskey(faceHash, f_a); if (f_b) - _f_b = BLI_ghash_haskey(faceHash, f_b); - if (_f_a ^ _f_b) { + has_f_b = BLI_ghash_haskey(faceHash, f_b); + if (has_f_a ^ has_f_b) { for (int i = 0; i < 2; i++) { BMVert *v = (i == 0) ? e->v1 : e->v2; @@ -269,7 +271,7 @@ static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *b zero_v3(n_final); copy_v3_v3(pow_a, f_a->no); copy_v3_v3(pow_b, f_b->no); - if (_f_a) { + if (has_f_a) { mul_v3_fl(pow_a, bmd->res / ref); mul_v3_fl(pow_b, ref / bmd->res); } @@ -286,7 +288,7 @@ static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *b } } } - else if(_f_a == true && _f_b == true) { + else if(has_f_a == true && has_f_b == true) { for (int i = 0; i < 2; i++) { BMVert *v = (i == 0) ? e->v1 : e->v2; BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) { @@ -409,13 +411,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp, dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp, bmd->hnmode, &bmd->clnordata); - if (bmd->value > 0 && bmd->hnmode != MOD_BEVEL_HN_NONE) { - if (bmd->hnmode != BEVEL_HN_FIX_SHA) - bevel_mod_harden_normals(bmd, bm, bmd->hn_strength, bmd->hnmode, dvert, vgroup); - else if(bmd->clnordata.faceHash && !vertex_only) - bevel_fix_normal_shading_continuity(bmd, bm); + if (bmd->hnmode != BEVEL_HN_FIX_SHA && bmd->hnmode != MOD_BEVEL_HN_NONE) { + bevel_mod_harden_normals(bmd, bm, bmd->hn_strength, bmd->hnmode, dvert, vgroup); } - + if(bmd->hnmode == BEVEL_HN_FIX_SHA) + bevel_fix_normal_shading_continuity(bmd, bm); if(set_wn_strength) bevel_set_weighted_normal_face_strength(bm, scene); -- cgit v1.2.3 From ef8ab3b4c2aa4b709acf6b4c8263ceb6d6f515de Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 1 Aug 2018 14:20:04 +0200 Subject: Fix issues after last 2.8 merge. --- source/blender/editors/mesh/editmesh_tools.c | 12 ++++++------ source/blender/modifiers/intern/MOD_bevel.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 0d11bf80366..d327e270a35 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -7358,7 +7358,7 @@ static int edbm_point_normals_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static bool point_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +static bool point_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) { const char *prop_id = RNA_property_identifier(prop); @@ -7380,7 +7380,7 @@ static void edbm_point_normals_ui(bContext *C, wmOperator *op) RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); /* Main auto-draw call */ - uiDefAutoButsRNA(layout, &ptr, point_normals_draw_check_prop, '\0', false); + uiDefAutoButsRNA(layout, &ptr, point_normals_draw_check_prop, NULL, '\0', false); } void MESH_OT_point_normals(struct wmOperatorType *ot) @@ -7751,7 +7751,7 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static bool average_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +static bool average_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) { const char *prop_id = RNA_property_identifier(prop); const int average_type = RNA_enum_get(ptr, "average_type"); @@ -7777,7 +7777,7 @@ static void edbm_average_normals_ui(bContext *C, wmOperator *op) RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); /* Main auto-draw call */ - uiDefAutoButsRNA(layout, &ptr, average_normals_draw_check_prop, '\0', false); + uiDefAutoButsRNA(layout, &ptr, average_normals_draw_check_prop, NULL, '\0', false); } void MESH_OT_average_normals(struct wmOperatorType *ot) @@ -7943,7 +7943,7 @@ static int edbm_normals_tools_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static bool normals_tools_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +static bool normals_tools_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) { const char *prop_id = RNA_property_identifier(prop); const int mode = RNA_enum_get(ptr, "mode"); @@ -7966,7 +7966,7 @@ static void edbm_normals_tools_ui(bContext *C, wmOperator *op) RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); /* Main auto-draw call */ - uiDefAutoButsRNA(layout, &ptr, normals_tools_draw_check_prop, '\0', false); + uiDefAutoButsRNA(layout, &ptr, normals_tools_draw_check_prop, NULL, '\0', false); } void MESH_OT_normals_tools(struct wmOperatorType *ot) diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 1ada8b215c5..cf0753334db 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -233,7 +233,7 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, const fl static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *bm) { const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0; - if (bmd->value == 0 || bmd->clnordata.faceHash == NULL && vertex_only) + if (bmd->value == 0 || (bmd->clnordata.faceHash == NULL && vertex_only)) return; BM_mesh_normals_update(bm); -- cgit v1.2.3 From 9a43ebdd5b5e7c8f4a4202d7eb2bcb3e33a2d76e Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 1 Aug 2018 14:29:36 +0200 Subject: Fix more merge stupid leftover, and some build warnings. --- release/scripts/startup/bl_ui/space_view3d_toolbar.py | 1 - source/blender/modifiers/intern/MOD_bevel.c | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 6110d0fca61..66bf08ed8d8 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1615,7 +1615,6 @@ class VIEW3D_PT_tools_grease_pencil_brushcurves(View3DPanel, Panel): # Grease Pencil create shapes class VIEW3D_PT_tools_grease_pencil_shapes(View3DPanel, Panel): ->>>>>>> blender2.8 bl_space_type = 'VIEW_3D' bl_region_type = 'HEADER' bl_label = "Shapes" diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index cf0753334db..3db4089138b 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -143,13 +143,14 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, const fl BMEdge *e_next; const BMEdge *e_org = l_cur->e; BMLoop *lfan_pivot, *lfan_pivot_next; + UNUSED_VARS_NDEBUG(v_pivot); lfan_pivot = l_cur; e_next = lfan_pivot->e; BLI_SMALLSTACK_DECLARE(loops, BMLoop *); float cn_wght[3] = { 0.0f, 0.0f, 0.0f }; int recon_face_count = 0; /* Reconstructed face */ - BMFace *recon_face; + BMFace *recon_face = NULL; while (true) { lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); @@ -165,7 +166,7 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, const fl if (bmd->lim_flags & MOD_BEVEL_WEIGHT) { int weight = BM_elem_float_data_get(&bm->edata, lfan_pivot->f, CD_BWEIGHT); if (weight) { - if (bmd->hnmode == MOD_BEVEL_HN_FACE) { + if (hnmode == MOD_BEVEL_HN_FACE) { float cur[3]; mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f)); add_v3_v3(cn_wght, cur); @@ -180,7 +181,7 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, const fl else if (bmd->lim_flags & MOD_BEVEL_VGROUP) { const bool has_vgroup = dvert != NULL; const bool vert_of_group = has_vgroup && defvert_find_index(&dvert[BM_elem_index_get(l->v)], vgroup) != NULL; - if (vert_of_group && bmd->hnmode == MOD_BEVEL_HN_FACE) { + if (vert_of_group && hnmode == MOD_BEVEL_HN_FACE) { float cur[3]; mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f)); add_v3_v3(cn_wght, cur); -- cgit v1.2.3 From cc004fd13cc6d5cf77d8bb1e33594662d63c7b13 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 1 Aug 2018 14:37:24 +0200 Subject: Some more minor typo fixes in comments. --- source/blender/blenkernel/intern/editmesh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index a7f93ca6c49..00e508e4d8f 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -251,10 +251,10 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em) { BMesh *bm = em->bm; - /* We need to create clnors data is none exist yet, otherwise there is no way to edit them. */ + /* We need to create clnors data if none exist yet, otherwise there is no way to edit them. */ /* Similar code to MESH_OT_customdata_custom_splitnormals_add operator, we want to keep same shading * in case we were using autosmooth so far... */ - /* Note: there is a problem here, which is that is someone starts a normal editing operation on previously + /* Note: there is a problem here, which is that if someone starts a normal editing operation on previously * autosmooth-ed mesh, and cancel that operation, generated clnors data remain, with related sharp edges * (and hence autosmooth is 'lost'). * Not sure how critical this is, and how to fix that issue? */ -- cgit v1.2.3 From 86f6c15809c672847bd8c62a9f166bf096ccd85c Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Sat, 4 Aug 2018 22:11:11 +0530 Subject: Removed redundant comment in BMesh --- release/scripts/addons | 2 +- source/blender/bmesh/bmesh_class.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/release/scripts/addons b/release/scripts/addons index 371960484a3..27970761a18 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit 371960484a38fc64e0a2635170a41a0d8ab2f6bd +Subproject commit 27970761a18926abe1b0020aa350305e3109a537 diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index 5ff1d2c970f..70884454ce5 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -238,7 +238,7 @@ typedef struct BMesh { struct BLI_mempool *looplistpool; #endif - struct MLoopNorSpaceArray *lnor_spacearr; /* Stores MLoopNorSpaceArray for this BMesh */ + struct MLoopNorSpaceArray *lnor_spacearr; char spacearr_dirty; /* should be copy of scene select mode */ -- cgit v1.2.3 From e8748e5ae7955b31c17c6cddb5e092202b39fcfd Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Sat, 4 Aug 2018 22:11:57 +0530 Subject: Fixed comment formatting in editmesh.c --- source/blender/blenkernel/intern/editmesh.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index 00e508e4d8f..7d66d25c58a 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -251,10 +251,10 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em) { BMesh *bm = em->bm; - /* We need to create clnors data if none exist yet, otherwise there is no way to edit them. */ - /* Similar code to MESH_OT_customdata_custom_splitnormals_add operator, we want to keep same shading - * in case we were using autosmooth so far... */ - /* Note: there is a problem here, which is that if someone starts a normal editing operation on previously + /* We need to create clnors data if none exist yet, otherwise there is no way to edit them. + * Similar code to MESH_OT_customdata_custom_splitnormals_add operator, we want to keep same shading + * in case we were using autosmooth so far... + * Note: there is a problem here, which is that if someone starts a normal editing operation on previously * autosmooth-ed mesh, and cancel that operation, generated clnors data remain, with related sharp edges * (and hence autosmooth is 'lost'). * Not sure how critical this is, and how to fix that issue? */ -- cgit v1.2.3 From 997b35f57a5454b5a43d47fddd84459bd19936f0 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Sat, 4 Aug 2018 22:31:53 +0530 Subject: Added comments on hn_mode, BMOps on bevel --- source/blender/bmesh/intern/bmesh_mesh.c | 2 -- source/blender/bmesh/intern/bmesh_opdefines.c | 10 +++++----- source/blender/bmesh/intern/bmesh_operators.h | 8 ++++---- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index 96707335081..4059cf27f23 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -320,7 +320,6 @@ void BM_mesh_free(BMesh *bm) */ /* We use that existing internal API flag, assuming no other tool using it would run concurrently to clnors editing. */ -/* XXX Should we rather add a new internal flag? */ #define BM_LNORSPACE_UPDATE _FLAG_MF typedef struct BMEdgesCalcVectorsData { @@ -1077,7 +1076,6 @@ void BM_lnorspacearr_store(BMesh *bm, float(*r_lnors)[3]) bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL); } -/* will change later */ #define CLEAR_SPACEARRAY_THRESHOLD(x) ((x) / 2) void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all) diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 49d160f5d4a..d9093e774e6 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1736,17 +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}, - {"mark_sharp", BMO_OP_SLOT_BOOL}, - {"strength", BMO_OP_SLOT_FLT}, - {"hnmode", BMO_OP_SLOT_INT}, + {"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}, + {"normals.out", BMO_OP_SLOT_MAPPING}, /* output normals per vertex for beveled edges */ {{'\0'}}, }, diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h index 9f6ac50a3e5..6d518545967 100644 --- a/source/blender/bmesh/intern/bmesh_operators.h +++ b/source/blender/bmesh/intern/bmesh_operators.h @@ -128,10 +128,10 @@ enum { }; enum { - BEVEL_HN_NONE, - BEVEL_HN_FACE, - BEVEL_HN_ADJ, - BEVEL_HN_FIX_SHA, + 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[]; -- cgit v1.2.3 From 7db1db72bbdd178e0c8da4b39bfa166a1f0e2f84 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Sat, 4 Aug 2018 22:32:28 +0530 Subject: Fixed hnmode not being passed with bevel tool --- source/blender/bmesh/operators/bmo_bevel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index cd27b486929..9d956c26390 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -66,7 +66,7 @@ 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, mark_seam, mark_sharp, 0/*hnmode*/, op); + 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); -- cgit v1.2.3 From cc30793a76fa058f53ed43f7515c6417128ffebe Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Sat, 4 Aug 2018 22:38:54 +0530 Subject: Added comments to seam and sharp len, removed unused var --- source/blender/bmesh/tools/bmesh_bevel.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index bcf44ad4384..f9555b324c3 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -152,8 +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; - int sharp_len; + 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; @@ -185,7 +185,6 @@ typedef struct BevVert { EdgeHalf *edges; /* array of size edgecount; CCW order from vertex normal side */ BMEdge **wire_edges; /* array of size wirecount of wire edges */ VMesh *vmesh; /* mesh structure for replacing vertex */ - bool fix_shading; } BevVert; /* Bevel parameters and state */ @@ -3209,8 +3208,6 @@ static VMesh *adj_vmesh(BevelParams *bp, BevVert *bv) return tri_corner_adj_vmesh(bp, bv); } - bv->fix_shading = true; - /* First construct an initial control mesh, with nseg==2 */ ns = bv->vmesh->seg; vm0 = new_adj_vmesh(mem_arena, n, 2, bv->vmesh->boundstart); -- cgit v1.2.3 From e5e9578881c0825e6bc0696818e3a4cdc939c371 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Sat, 4 Aug 2018 23:20:53 +0530 Subject: Added comments to functionality in main bevel code --- source/blender/bmesh/tools/bmesh_bevel.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index f9555b324c3..79310deef2a 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -1537,15 +1537,19 @@ 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; - efirst = e; + efirst = e; /* Set efirst to this first encountered edge*/ + do { int flag_count = 0; EdgeHalf *ne = e->next; @@ -1559,13 +1563,12 @@ static void check_edge_data_seam_sharp_edges(BevVert *bv, int flag, bool neg) (neg && BEV_EXTEND_EDGE_DATA_CHECK(efirst, flag))))) { break; } - if (flag == BM_ELEM_SEAM) + if (flag == BM_ELEM_SEAM) /* Set seam_len / sharp_len of starting edge */ 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) @@ -1575,10 +1578,14 @@ static void bevel_extend_edge_data(BevVert *bv) 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; + 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; @@ -1586,6 +1593,7 @@ static void bevel_extend_edge_data(BevVert *bv) 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) @@ -1597,7 +1605,7 @@ static void bevel_extend_edge_data(BevVert *bv) v1 = v2; } BMVert *v3 = mesh_vert(vm, (i + 1) % vm->count, 0, 0)->v; - e = v1->e; + 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; @@ -1672,6 +1680,7 @@ static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, B 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)) { @@ -1714,6 +1723,7 @@ static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, B } 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__); -- cgit v1.2.3 From 435d731c6fcc5ea106264317bc5c669ebc27ad7f Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Sat, 4 Aug 2018 23:36:00 +0530 Subject: Added some comments to bevel_harden_normals for bev tool --- source/blender/editors/mesh/editmesh_bevel.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 51bfaaf61e5..442eef927af 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -147,20 +147,23 @@ static void bevel_harden_normals(BMEditMesh *em, BMOperator *bmop, float face_st BMLoop *l, *l_cur, *l_first; BMIter fiter; - BMOpSlot *nslot = BMO_slot_get(bmop->slots_out, "normals.out"); + BMOpSlot *nslot = BMO_slot_get(bmop->slots_out, "normals.out"); /* Per vertex normals depending on hn_mode */ + /* Similar functionality to bm_mesh_loops_calc_normals... Edges that can be smoothed are tagged */ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { l_cur = l_first = BM_FACE_FIRST_LOOP(f); do { if (BM_elem_flag_test(l_cur->v, BM_ELEM_SELECT) && (!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) || (!BM_elem_flag_test(l_cur, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_cur)))) { + /* Both adjacent loops are sharp, set clnor to face normal */ if (!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_cur->prev->e, BM_ELEM_TAG)) { const int loop_index = BM_elem_index_get(l_cur); short *clnors = BM_ELEM_CD_GET_VOID_P(l_cur, cd_clnors_offset); BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors); } else { + /* Find next corresponding sharp edge in this smooth fan */ BMVert *v_pivot = l_cur->v; float *calc_n = BLI_ghash_lookup(nslot->data.ghash, v_pivot); @@ -173,6 +176,7 @@ static void bevel_harden_normals(BMEditMesh *em, BMOperator *bmop, float face_st BLI_SMALLSTACK_DECLARE(loops, BMLoop *); float cn_wght[3] = { 0.0f, 0.0f, 0.0f }, cn_unwght[3] = { 0.0f, 0.0f, 0.0f }; + /* Fan through current vert and accumulate normals and loops */ while (true) { lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); if (lfan_pivot_next) { -- cgit v1.2.3 From 710d2def6509d2c993cb96f42eb1a97ccc60bfcf Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Sat, 4 Aug 2018 23:38:12 +0530 Subject: Initialized normal data in BevMod --- source/blender/modifiers/intern/MOD_bevel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 3db4089138b..152fee9eb77 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -70,7 +70,9 @@ static void initData(ModifierData *md) bmd->profile = 0.5f; bmd->bevel_angle = DEG2RADF(30.0f); bmd->defgrp_name[0] = '\0'; + bmd->hnmode = MOD_BEVEL_HN_NONE; bmd->hn_strength = 0.5f; + bmd->clnordata.faceHash = NULL; } static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) -- cgit v1.2.3 From c41ce58fdeba46dd96dccd7d2b98b1d3f5de726e Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Sun, 5 Aug 2018 08:39:20 +0530 Subject: Fix indentation, spacing and added comments --- source/blender/bmesh/intern/bmesh_mesh.c | 15 ++++--- source/blender/bmesh/operators/bmo_bevel.c | 3 +- source/blender/bmesh/tools/bmesh_bevel.c | 15 ++++--- source/blender/editors/mesh/editmesh_bevel.c | 16 ++++--- source/blender/editors/mesh/editmesh_tools.c | 6 ++- source/blender/modifiers/intern/MOD_bevel.c | 51 ++++++++++++++-------- .../blender/modifiers/intern/MOD_weighted_normal.c | 6 ++- 7 files changed, 72 insertions(+), 40 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index 4059cf27f23..292453fac4b 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -1114,9 +1114,10 @@ void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all) /* 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) && + 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) { @@ -1125,9 +1126,10 @@ void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all) BLI_BITMAP_ENABLE(done_verts, BM_elem_index_get(l_prev->v)); } - if (!BM_elem_flag_test(l->next->v, BM_ELEM_SELECT) && + 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) { @@ -1172,7 +1174,8 @@ void BM_lnorspace_rebuild(BMesh *bm, bool 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_data_to_normal(bm->lnor_spacearr->lspacearr[l_index], *clnor, oldnors[l_index]); + BKE_lnor_space_custom_data_to_normal(bm->lnor_spacearr->lspacearr[l_index], *clnor, + oldnors[l_index]); } } } @@ -1191,7 +1194,8 @@ void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor) 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); + 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); } @@ -1398,7 +1402,8 @@ BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm) 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__); + 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); diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 9d956c26390..eb299dbba60 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -66,7 +66,8 @@ 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, mark_seam, mark_sharp, hnmode, op); + 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/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 79310deef2a..b45c9e295ab 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -1554,16 +1554,19 @@ static void check_edge_data_seam_sharp_edges(BevVert *bv, int flag, bool neg) 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) { + 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))))) { + (neg && BEV_EXTEND_EDGE_DATA_CHECK(efirst, flag))))) + { break; } - if (flag == BM_ELEM_SEAM) /* Set seam_len / sharp_len of starting edge */ + if (flag == BM_ELEM_SEAM) /* Set seam_len / sharp_len of starting edge */ e->rightv->seam_len = flag_count; else if (flag == BM_ELEM_SMOOTH) e->rightv->sharp_len = flag_count; @@ -1687,7 +1690,7 @@ static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, B 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)))) { + 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); @@ -1695,7 +1698,7 @@ static void bevel_harden_normals_mode(BMesh *bm, BevelParams *bp, BevVert *bv, B 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)))) { + 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); @@ -3794,7 +3797,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv) NULL, bme1, bme2, bme3, mat_nr); } } - if(do_fix_shading_bv) + if (do_fix_shading_bv) BLI_ghash_insert(bp->faceHash, r_f, NULL); } } diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 442eef927af..931e395736f 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -153,7 +153,8 @@ static void bevel_harden_normals(BMEditMesh *em, BMOperator *bmop, float face_st BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { l_cur = l_first = BM_FACE_FIRST_LOOP(f); do { - if (BM_elem_flag_test(l_cur->v, BM_ELEM_SELECT) && (!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) || + if ((BM_elem_flag_test(l_cur->v, BM_ELEM_SELECT)) && + ((!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG)) || (!BM_elem_flag_test(l_cur, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_cur)))) { /* Both adjacent loops are sharp, set clnor to face normal */ @@ -191,7 +192,7 @@ static void bevel_harden_normals(BMEditMesh *em, BMOperator *bmop, float face_st mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f)); add_v3_v3(cn_wght, cur); - if(BM_elem_flag_test(lfan_pivot->f, BM_ELEM_SELECT)) + if (BM_elem_flag_test(lfan_pivot->f, BM_ELEM_SELECT)) add_v3_v3(cn_unwght, cur); if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { @@ -215,7 +216,8 @@ static void bevel_harden_normals(BMEditMesh *em, BMOperator *bmop, float face_st BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], calc_n, clnors); } else - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], cn_unwght, clnors); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], cn_unwght, + clnors); } BLI_ghash_remove(nslot->data.ghash, v_pivot, NULL, MEM_freeN); } @@ -347,7 +349,7 @@ static bool edbm_bevel_calc(wmOperator *op) BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); } - if(hnmode != BEVEL_HN_NONE) + if (hnmode != BEVEL_HN_NONE) bevel_harden_normals(em, &bmop, hn_strength, hnmode); /* no need to de-select existing geometry */ @@ -794,6 +796,8 @@ void MESH_OT_bevel(wmOperatorType *ot) RNA_def_boolean(ot->srna, "mark_sharp", false, "Mark Sharp", "Mark beveled edges as sharp"); RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100); - RNA_def_float(ot->srna, "strength", 0.5f, 0.0f, 1.0f, "Normal Strength", "Strength of calculated normal", 0.0f, 1.0f); - RNA_def_enum(ot->srna, "hnmode", harden_normals_items, BEVEL_HN_NONE, "Normal Mode", "Weighting mode for Harden Normals"); + RNA_def_float(ot->srna, "strength", 0.5f, 0.0f, 1.0f, "Normal Strength", + "Strength of calculated normal", 0.0f, 1.0f); + RNA_def_enum(ot->srna, "hnmode", harden_normals_items, BEVEL_HN_NONE, "Normal Mode", + "Weighting mode for Harden Normals"); } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index d327e270a35..d94d3051b50 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -7063,7 +7063,8 @@ static void point_normals_update_header(bContext *C, wmOperator *op) WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_RESET), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_INVERT), WM_bool_as_string(RNA_boolean_get(op->ptr, "invert")), - WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SPHERIZE), WM_bool_as_string(RNA_boolean_get(op->ptr, "spherize")), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SPHERIZE), + WM_bool_as_string(RNA_boolean_get(op->ptr, "spherize")), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_ALIGN), WM_bool_as_string(RNA_boolean_get(op->ptr, "align"))); #undef WM_MODALKEY @@ -8063,7 +8064,8 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op) if (BLI_BITMAP_TEST(loop_set, BM_elem_index_get(l))) { const int loop_index = BM_elem_index_get(l); short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], vnors[v_index], clnors); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], vnors[v_index], + clnors); } } } diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 152fee9eb77..f1dc73436ee 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -110,7 +110,9 @@ static void bevel_set_weighted_normal_face_strength(BMesh *bm, Scene *scene) } } -static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, const float hn_strength, const int hnmode, MDeformVert *dvert, int vgroup) +static void bevel_mod_harden_normals( + BevelModifierData *bmd, BMesh *bm, const float hn_strength, + const int hnmode, MDeformVert *dvert, int vgroup) { if (bmd->res > 20 || bmd->value == 0) return; @@ -128,13 +130,16 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, const fl BMIter fiter; GHash *faceHash = bmd->clnordata.faceHash; + /* Iterate throught all loops of a face */ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { l_cur = l_first = BM_FACE_FIRST_LOOP(f); do { - if ((!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) || (!BM_elem_flag_test(l_cur, BM_ELEM_TAG) && - BM_loop_check_cyclic_smooth_fan(l_cur)))) { + if ((!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG)) || + (!BM_elem_flag_test(l_cur, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_cur))) + { + /* previous and next edge is sharp, accumulate face normals into loop */ if (!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_cur->prev->e, BM_ELEM_TAG)) { const int loop_index = BM_elem_index_get(l_cur); short *clnors = BM_ELEM_CD_GET_VOID_P(l_cur, cd_clnors_offset); @@ -151,8 +156,8 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, const fl e_next = lfan_pivot->e; BLI_SMALLSTACK_DECLARE(loops, BMLoop *); float cn_wght[3] = { 0.0f, 0.0f, 0.0f }; - int recon_face_count = 0; /* Reconstructed face */ - BMFace *recon_face = NULL; + int recon_face_count = 0; /* Counts number of reconstructed faces current vert is connected to */ + BMFace *recon_face = NULL; /* Reconstructed face */ while (true) { lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next); @@ -169,12 +174,12 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, const fl int weight = BM_elem_float_data_get(&bm->edata, lfan_pivot->f, CD_BWEIGHT); if (weight) { if (hnmode == MOD_BEVEL_HN_FACE) { - float cur[3]; + float cur[3]; //Add area weighted face normals mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f)); add_v3_v3(cn_wght, cur); } else - add_v3_v3(cn_wght, lfan_pivot->f->no); + add_v3_v3(cn_wght, lfan_pivot->f->no); //Else simply add face normals } else add_v3_v3(cn_wght, lfan_pivot->f->no); @@ -182,7 +187,9 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, const fl } else if (bmd->lim_flags & MOD_BEVEL_VGROUP) { const bool has_vgroup = dvert != NULL; - const bool vert_of_group = has_vgroup && defvert_find_index(&dvert[BM_elem_index_get(l->v)], vgroup) != NULL; + const bool vert_of_group = has_vgroup && + (defvert_find_index(&dvert[BM_elem_index_get(l->v)], vgroup) != NULL); + if (vert_of_group && hnmode == MOD_BEVEL_HN_FACE) { float cur[3]; mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f)); @@ -214,18 +221,22 @@ static void bevel_mod_harden_normals(BevelModifierData *bmd, BMesh *bm, const fl const int l_index = BM_elem_index_get(l); short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + /* If vertex is edge vert with 1 reconnected face */ if (recon_face_count == 1 || do_normal_to_recon) { - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], recon_face->no, clnors); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], recon_face->no, + clnors); } else if (vertex_only == false || recon_face_count == 0) { copy_v3_v3(n_final, l->f->no); mul_v3_fl(n_final, 1.0f - hn_strength); add_v3_v3(n_final, cn_wght); normalize_v3(n_final); - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, + clnors); } - else if(BLI_ghash_haskey(faceHash, l->f)) - BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], l->v->no, clnors); + else if (BLI_ghash_haskey(faceHash, l->f)) + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], l->v->no, + clnors); } } } @@ -261,6 +272,8 @@ static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *b if (f_b) has_f_b = BLI_ghash_haskey(faceHash, f_b); if (has_f_a ^ has_f_b) { + /* If one of both faces is present in faceHash then we are at a border + * between new vmesh created and reconstructed face */ for (int i = 0; i < 2; i++) { BMVert *v = (i == 0) ? e->v1 : e->v2; @@ -291,12 +304,14 @@ static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *b } } } - else if(has_f_a == true && has_f_b == true) { + else if (has_f_a == true && has_f_b == true) { + /* Else if both faces are present we assign clnor corresponding + * to vert normal and face normal */ for (int i = 0; i < 2; i++) { BMVert *v = (i == 0) ? e->v1 : e->v2; BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) { - if(l->f == f_a || l->f == f_b) { + if (l->f == f_a || l->f == f_b) { const int l_index = BM_elem_index_get(l); short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); float n_final[3], cn_wght[3]; @@ -417,9 +432,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes if (bmd->hnmode != BEVEL_HN_FIX_SHA && bmd->hnmode != MOD_BEVEL_HN_NONE) { bevel_mod_harden_normals(bmd, bm, bmd->hn_strength, bmd->hnmode, dvert, vgroup); } - if(bmd->hnmode == BEVEL_HN_FIX_SHA) + if (bmd->hnmode == BEVEL_HN_FIX_SHA) bevel_fix_normal_shading_continuity(bmd, bm); - if(set_wn_strength) + if (set_wn_strength) bevel_set_weighted_normal_face_strength(bm, scene); result = BKE_bmesh_to_mesh_nomain(bm, &(struct BMeshToMeshParams){0}); @@ -429,7 +444,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes bm->ftoolflagpool == NULL); /* make sure we never alloc'd these */ BM_mesh_free(bm); - if(bmd->clnordata.faceHash) + if (bmd->clnordata.faceHash) BLI_ghash_free(bmd->clnordata.faceHash, NULL, NULL); result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; @@ -450,7 +465,7 @@ ModifierTypeInfo modifierType_Bevel = { /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode | - eModifierTypeFlag_AcceptsCVs, + eModifierTypeFlag_AcceptsCVs, /* copyData */ modifier_copyData_generic, diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index a2ace1aadc4..3e788db9c00 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -217,7 +217,8 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, Weight num_items = lnors_spacearr.num_spaces; items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__); - /* In this first loop, we assign each WeightedNormalDataAggregateItem to its smooth fan of loops (aka lnor space). */ + /* In this first loop, we assign each WeightedNormalDataAggregateItem + * to its smooth fan of loops (aka lnor space). */ MPoly *mp; int mp_index; int item_index; @@ -572,7 +573,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes .mpoly = mpoly, .polynors = polynors, - .poly_strength = CustomData_get_layer_named(&result->pdata, CD_PROP_INT, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID), + .poly_strength = CustomData_get_layer_named(&result->pdata, CD_PROP_INT, + MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID), .dvert = dvert, .defgrp_index = defgrp_index, -- cgit v1.2.3 From aa41c866364178fa0057bd93fd17718f59aa101a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 8 Aug 2018 20:45:43 +1000 Subject: Cleanup: trailing space --- release/scripts/startup/bl_ui/properties_data_modifier.py | 4 ++-- source/blender/bmesh/tools/bmesh_bevel.c | 2 +- source/blender/editors/mesh/editmesh_bevel.c | 2 +- source/blender/editors/mesh/editmesh_tools.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index f2ed4b3b88c..1671cf7736d 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -147,7 +147,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "loop_slide") col.prop(md, "mark_seam") col.prop(md, "mark_sharp") - + layout.label(text="Limit Method:") layout.row().prop(md, "limit_method", expand=True) if md.limit_method == 'ANGLE': @@ -158,7 +158,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): layout.label(text="Width Method:") layout.row().prop(md, "offset_type", expand=True) - + layout.label(text="Normal Mode") layout.row().prop(md, "hnmode", expand=True) layout.prop(md, "hn_strength") diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index b45c9e295ab..58380491a10 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -1553,7 +1553,7 @@ static void check_edge_data_seam_sharp_edges(BevVert *bv, int flag, bool neg) 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) { diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 931e395736f..8d1832e84a4 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -722,7 +722,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) handled = true; break; } - + } /* Modal numinput inactive, try to handle numeric inputs last... */ diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index d94d3051b50..45ffd3245a3 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -7063,7 +7063,7 @@ static void point_normals_update_header(bContext *C, wmOperator *op) WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_RESET), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_INVERT), WM_bool_as_string(RNA_boolean_get(op->ptr, "invert")), - WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SPHERIZE), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SPHERIZE), WM_bool_as_string(RNA_boolean_get(op->ptr, "spherize")), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_ALIGN), WM_bool_as_string(RNA_boolean_get(op->ptr, "align"))); -- cgit v1.2.3 From 42c2066d08216bb57492fef441ee20217444d395 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Thu, 9 Aug 2018 18:36:38 +0530 Subject: Fixed custom shading not updating in Edit Mode --- source/blender/draw/intern/draw_cache_impl_mesh.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 87737fae820..ba16dab0623 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -427,7 +427,9 @@ static MeshRenderData *mesh_render_data_create_ex( int totloop = bm->totloop; if (is_auto_smooth) { rdata->loop_normals = MEM_mallocN(sizeof(*rdata->loop_normals) * totloop, __func__); - BM_loops_calc_normal_vcos(bm, NULL, NULL, NULL, true, split_angle, rdata->loop_normals, NULL, NULL, -1, false); + int cd_loop_clnors_offset = CustomData_get_clone_layer_index(&bm->ldata, CD_CUSTOMLOOPNORMAL); + BM_loops_calc_normal_vcos(bm, NULL, NULL, NULL, true, split_angle, rdata->loop_normals, NULL, NULL, + cd_loop_clnors_offset, false); } rdata->loop_len = totloop; bm_ensure_types |= BM_LOOP; -- cgit v1.2.3 From fea5f26ea56acd73d043e97a96d06067b24ef811 Mon Sep 17 00:00:00 2001 From: Rohan Rathi Date: Thu, 9 Aug 2018 18:56:46 +0530 Subject: Fix trivial error in call --- source/blender/draw/intern/draw_cache_impl_mesh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index ba16dab0623..dcfb9229cc1 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -427,7 +427,7 @@ static MeshRenderData *mesh_render_data_create_ex( int totloop = bm->totloop; if (is_auto_smooth) { rdata->loop_normals = MEM_mallocN(sizeof(*rdata->loop_normals) * totloop, __func__); - int cd_loop_clnors_offset = CustomData_get_clone_layer_index(&bm->ldata, CD_CUSTOMLOOPNORMAL); + int cd_loop_clnors_offset = CustomData_get_layer_index(&bm->ldata, CD_CUSTOMLOOPNORMAL); BM_loops_calc_normal_vcos(bm, NULL, NULL, NULL, true, split_angle, rdata->loop_normals, NULL, NULL, cd_loop_clnors_offset, false); } -- cgit v1.2.3