Add miter pattern options.
[blender.git] / source / blender / modifiers / intern / MOD_bevel.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software  Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Daniel Dunbar
22  *                 Ton Roosendaal,
23  *                 Ben Batt,
24  *                 Brecht Van Lommel,
25  *                 Campbell Barton
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  *
29  */
30
31 /** \file blender/modifiers/intern/MOD_bevel.c
32  *  \ingroup modifiers
33  */
34
35 #include "MEM_guardedalloc.h"
36
37 #include "DNA_mesh_types.h"
38 #include "DNA_meshdata_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_scene_types.h"
41
42 #include "BLI_utildefines.h"
43 #include "BLI_linklist_stack.h"
44 #include "BLI_math.h"
45 #include "BLI_string.h"
46
47 #include "BKE_deform.h"
48 #include "BKE_mesh.h"
49 #include "BKE_modifier.h"
50
51 #include "MOD_util.h"
52
53 #include "bmesh.h"
54 #include "bmesh_tools.h"
55
56 #include "DEG_depsgraph_query.h"
57
58 static void initData(ModifierData *md)
59 {
60         BevelModifierData *bmd = (BevelModifierData *) md;
61
62         bmd->value = 0.1f;
63         bmd->res = 1;
64         bmd->flags = 0;
65         bmd->val_flags = MOD_BEVEL_AMT_OFFSET;
66         bmd->lim_flags = 0;
67         bmd->e_flags = 0;
68         bmd->edge_flags = 0;
69         bmd->face_str_mode = MOD_BEVEL_FACE_STRENGTH_NONE;
70         bmd->miter_inner = MOD_BEVEL_MITER_SHARP;
71         bmd->miter_outer = MOD_BEVEL_MITER_SHARP;
72         bmd->spread = 0.1f;
73         bmd->mat = -1;
74         bmd->profile = 0.5f;
75         bmd->bevel_angle = DEG2RADF(30.0f);
76         bmd->defgrp_name[0] = '\0';
77         bmd->clnordata.faceHash = NULL;
78 }
79
80 static void copyData(const ModifierData *md_src, ModifierData *md_dst, const int flag)
81 {
82         BevelModifierData *bmd_dst = (BevelModifierData *)md_dst;
83
84         modifier_copyData_generic(md_src, md_dst, flag);
85
86         bmd_dst->clnordata.faceHash = NULL;
87 }
88
89 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
90 {
91         BevelModifierData *bmd = (BevelModifierData *)md;
92         CustomDataMask dataMask = 0;
93
94         /* ask for vertexgroups if we need them */
95         if (bmd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
96
97         return dataMask;
98 }
99
100 /*
101  * This calls the new bevel code (added since 2.64)
102  */
103 static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
104 {
105         Mesh *result;
106         BMesh *bm;
107         BMIter iter;
108         BMEdge *e;
109         BMVert *v;
110         float weight, weight2;
111         int vgroup = -1;
112         MDeformVert *dvert = NULL;
113         BevelModifierData *bmd = (BevelModifierData *) md;
114         const float threshold = cosf(bmd->bevel_angle + 0.000000175f);
115         const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0;
116         const bool do_clamp = !(bmd->flags & MOD_BEVEL_OVERLAP_OK);
117         const int offset_type = bmd->val_flags;
118         const float value = bmd->value;
119         const int mat = CLAMPIS(bmd->mat, -1, ctx->object->totcol - 1);
120         const bool loop_slide = (bmd->flags & MOD_BEVEL_EVEN_WIDTHS) == 0;
121         const bool mark_seam = (bmd->edge_flags & MOD_BEVEL_MARK_SEAM);
122         const bool mark_sharp = (bmd->edge_flags & MOD_BEVEL_MARK_SHARP);
123         bool harden_normals = (bmd->flags & MOD_BEVEL_HARDEN_NORMALS);
124         const int face_strength_mode = bmd->face_str_mode;
125         const int miter_outer = bmd->miter_outer;
126         const int miter_inner = bmd->miter_inner;
127         const float spread = bmd->spread;
128
129         bm = BKE_mesh_to_bmesh_ex(
130                 mesh,
131                 &(struct BMeshCreateParams){0},
132                 &(struct BMeshFromMeshParams){
133                     .calc_face_normal = true,
134                     .add_key_index = false,
135                     .use_shapekey = true,
136                     .active_shapekey = ctx->object->shapenr,
137                     .cd_mask_extra = CD_MASK_ORIGINDEX,
138                 });
139
140         if ((bmd->lim_flags & MOD_BEVEL_VGROUP) && bmd->defgrp_name[0])
141                 MOD_get_vgroup(ctx->object, mesh, bmd->defgrp_name, &dvert, &vgroup);
142
143         if (vertex_only) {
144                 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
145                         if (!BM_vert_is_manifold(v))
146                                 continue;
147                         if (bmd->lim_flags & MOD_BEVEL_WEIGHT) {
148                                 weight = BM_elem_float_data_get(&bm->vdata, v, CD_BWEIGHT);
149                                 if (weight == 0.0f)
150                                         continue;
151                         }
152                         else if (vgroup != -1) {
153                                 weight = defvert_array_find_weight_safe(dvert, BM_elem_index_get(v), vgroup);
154                                 /* Check is against 0.5 rather than != 0.0 because cascaded bevel modifiers will
155                                  * interpolate weights for newly created vertices, and may cause unexpected "selection" */
156                                 if (weight < 0.5f)
157                                         continue;
158                         }
159                         BM_elem_flag_enable(v, BM_ELEM_TAG);
160                 }
161         }
162         else if (bmd->lim_flags & MOD_BEVEL_ANGLE) {
163                 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
164                         /* check for 1 edge having 2 face users */
165                         BMLoop *l_a, *l_b;
166                         if (BM_edge_loop_pair(e, &l_a, &l_b)) {
167                                 if (dot_v3v3(l_a->f->no, l_b->f->no) < threshold) {
168                                         BM_elem_flag_enable(e, BM_ELEM_TAG);
169                                         BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
170                                         BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
171                                 }
172                         }
173                 }
174         }
175         else {
176                 /* crummy, is there a way just to operator on all? - campbell */
177                 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
178                         if (BM_edge_is_manifold(e)) {
179                                 if (bmd->lim_flags & MOD_BEVEL_WEIGHT) {
180                                         weight = BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT);
181                                         if (weight == 0.0f)
182                                                 continue;
183                                 }
184                                 else if (vgroup != -1) {
185                                         weight = defvert_array_find_weight_safe(dvert, BM_elem_index_get(e->v1), vgroup);
186                                         weight2 = defvert_array_find_weight_safe(dvert, BM_elem_index_get(e->v2), vgroup);
187                                         if (weight < 0.5f || weight2 < 0.5f)
188                                                 continue;
189                                 }
190                                 BM_elem_flag_enable(e, BM_ELEM_TAG);
191                                 BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
192                                 BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
193                         }
194                 }
195         }
196
197         if (harden_normals && !(((Mesh *)ctx->object->data)->flag & ME_AUTOSMOOTH)) {
198                 modifier_setError(md, "Enable 'Auto Smooth' option in mesh settings for hardening");
199                 harden_normals = false;
200         }
201
202         BM_mesh_bevel(bm, value, offset_type, bmd->res, bmd->profile,
203                       vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp,
204                       dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp,
205                       harden_normals, face_strength_mode,
206                       miter_outer, miter_inner, spread, mesh->smoothresh);
207
208         result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0);
209
210         BLI_assert(bm->vtoolflagpool == NULL &&
211                    bm->etoolflagpool == NULL &&
212                    bm->ftoolflagpool == NULL);  /* make sure we never alloc'd these */
213         BM_mesh_free(bm);
214
215         if (bmd->clnordata.faceHash)
216                 BLI_ghash_free(bmd->clnordata.faceHash, NULL, NULL);
217
218         result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
219
220         return result;
221 }
222
223 static bool dependsOnNormals(ModifierData *UNUSED(md))
224 {
225         return true;
226 }
227
228 ModifierTypeInfo modifierType_Bevel = {
229         /* name */              "Bevel",
230         /* structName */        "BevelModifierData",
231         /* structSize */        sizeof(BevelModifierData),
232         /* type */              eModifierTypeType_Constructive,
233         /* flags */             eModifierTypeFlag_AcceptsMesh |
234                                 eModifierTypeFlag_SupportsEditmode |
235                                 eModifierTypeFlag_EnableInEditmode |
236                                 eModifierTypeFlag_AcceptsCVs,
237
238         /* copyData */          copyData,
239
240         /* deformVerts_DM */    NULL,
241         /* deformMatrices_DM */ NULL,
242         /* deformVertsEM_DM */  NULL,
243         /* deformMatricesEM_DM*/NULL,
244         /* applyModifier_DM */  NULL,
245
246         /* deformVerts */       NULL,
247         /* deformMatrices */    NULL,
248         /* deformVertsEM */     NULL,
249         /* deformMatricesEM */  NULL,
250         /* applyModifier */     applyModifier,
251
252         /* initData */          initData,
253         /* requiredDataMask */  requiredDataMask,
254         /* freeData */          NULL,
255         /* isDisabled */        NULL,
256         /* updateDepsgraph */   NULL,
257         /* dependsOnTime */     NULL,
258         /* dependsOnNormals */  dependsOnNormals,
259         /* foreachObjectLink */ NULL,
260         /* foreachIDLink */     NULL,
261         /* foreachTexLink */    NULL,
262 };