2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
19 * All rights reserved.
21 * Contributor(s): Campbell Barton
25 * ***** END GPL LICENSE BLOCK *****
29 /** \file blender/modifiers/intern/MOD_solidify.c
33 #include "DNA_mesh_types.h"
34 #include "DNA_meshdata_types.h"
36 #include "MEM_guardedalloc.h"
38 #include "BLI_utildefines.h"
39 #include "BLI_stackdefines.h"
40 #include "BLI_bitmap.h"
43 #include "BKE_cdderivedmesh.h"
45 #include "BKE_particle.h"
46 #include "BKE_deform.h"
48 #include "MOD_modifiertypes.h"
52 # pragma GCC diagnostic error "-Wsign-conversion"
55 /* skip shell thickness for non-manifold edges, see [#35710] */
56 #define USE_NONMANIFOLD_WORKAROUND
58 /* *** derived mesh high quality normal calculation function *** */
59 /* could be exposed for other functions to use */
61 typedef struct EdgeFaceRef {
62 int f1; /* init as -1 */
66 BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref)
68 return !((edge_ref->f1 == 0) && (edge_ref->f2 == 0));
72 * \param dm Mesh to calculate normals for.
73 * \param face_nors Precalculated face normals.
74 * \param r_vert_nors Return vert normals.
76 static void dm_calc_normal(DerivedMesh *dm, float (*face_nors)[3], float (*r_vert_nors)[3])
78 int i, numVerts, numEdges, numFaces;
84 numVerts = dm->getNumVerts(dm);
85 numEdges = dm->getNumEdges(dm);
86 numFaces = dm->getNumPolys(dm);
87 mpoly = dm->getPolyArray(dm);
88 medge = dm->getEdgeArray(dm);
89 mvert = dm->getVertArray(dm);
90 mloop = dm->getLoopArray(dm);
92 /* we don't want to overwrite any referenced layers */
94 /* Doesn't work here! */
96 mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts);
104 EdgeFaceRef *edge_ref_array = MEM_callocN(sizeof(EdgeFaceRef) * (size_t)numEdges, "Edge Connectivity");
105 EdgeFaceRef *edge_ref;
106 float edge_normal[3];
108 /* This loop adds an edge hash if its not there, and adds the face index */
109 for (i = 0; i < numFaces; i++, mp++) {
112 ml = mloop + mp->loopstart;
114 for (j = 0; j < mp->totloop; j++, ml++) {
115 /* --- add edge ref to face --- */
116 edge_ref = &edge_ref_array[ml->e];
117 if (!edgeref_is_init(edge_ref)) {
121 else if ((edge_ref->f1 != -1) && (edge_ref->f2 == -1)) {
125 /* 3+ faces using an edge, we can't handle this usefully */
126 edge_ref->f1 = edge_ref->f2 = -1;
127 #ifdef USE_NONMANIFOLD_WORKAROUND
128 medge[ml->e].flag |= ME_EDGE_TMP_TAG;
135 for (i = 0, ed = medge, edge_ref = edge_ref_array; i < numEdges; i++, ed++, edge_ref++) {
136 /* Get the edge vert indices, and edge value (the face indices that use it) */
138 if (edgeref_is_init(edge_ref) && (edge_ref->f1 != -1)) {
139 if (edge_ref->f2 != -1) {
140 /* We have 2 faces using this edge, calculate the edges normal
141 * using the angle between the 2 faces as a weighting */
143 add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
144 normalize_v3(edge_normal);
146 mul_v3_fl(edge_normal, angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
148 mid_v3_v3v3_angle_weighted(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
152 /* only one face attached to that edge */
153 /* an edge without another attached- the weight on this is undefined */
154 copy_v3_v3(edge_normal, face_nors[edge_ref->f1]);
156 add_v3_v3(r_vert_nors[ed->v1], edge_normal);
157 add_v3_v3(r_vert_nors[ed->v2], edge_normal);
160 MEM_freeN(edge_ref_array);
163 /* normalize vertex normals and assign */
164 for (i = 0; i < numVerts; i++, mv++) {
165 if (normalize_v3(r_vert_nors[i]) == 0.0f) {
166 normal_short_to_float_v3(r_vert_nors[i], mv->no);
171 static void initData(ModifierData *md)
173 SolidifyModifierData *smd = (SolidifyModifierData *) md;
175 smd->offset_fac = -1.0f;
176 smd->flag = MOD_SOLIDIFY_RIM;
179 static void copyData(ModifierData *md, ModifierData *target)
182 SolidifyModifierData *smd = (SolidifyModifierData *) md;
183 SolidifyModifierData *tsmd = (SolidifyModifierData *) target;
185 modifier_copyData_generic(md, target);
188 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
190 SolidifyModifierData *smd = (SolidifyModifierData *) md;
191 CustomDataMask dataMask = 0;
193 /* ask for vertexgroups if we need them */
194 if (smd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
199 /* specific function for solidify - define locally */
200 BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f)
202 r[0] += (float)a[0] * f;
203 r[1] += (float)a[1] * f;
204 r[2] += (float)a[2] * f;
207 static DerivedMesh *applyModifier(
208 ModifierData *md, Object *ob,
210 ModifierApplyFlag UNUSED(flag))
214 const SolidifyModifierData *smd = (SolidifyModifierData *) md;
216 MVert *mv, *mvert, *orig_mvert;
217 MEdge *ed, *medge, *orig_medge;
218 MLoop *ml, *mloop, *orig_mloop;
219 MPoly *mp, *mpoly, *orig_mpoly;
220 const unsigned int numVerts = (unsigned int)dm->getNumVerts(dm);
221 const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
222 const unsigned int numFaces = (unsigned int)dm->getNumPolys(dm);
223 const unsigned int numLoops = (unsigned int)dm->getNumLoops(dm);
224 unsigned int newLoops = 0, newFaces = 0, newEdges = 0, newVerts = 0;
226 /* only use material offsets if we have 2 or more materials */
227 const short mat_nr_max = ob->totcol > 1 ? ob->totcol - 1 : 0;
228 const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0;
229 const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0;
232 /* over-alloc new_vert_arr, old_vert_arr */
233 unsigned int *new_vert_arr = NULL;
234 STACK_DECLARE(new_vert_arr);
236 unsigned int *new_edge_arr = NULL;
237 STACK_DECLARE(new_edge_arr);
239 unsigned int *old_vert_arr = MEM_callocN(sizeof(*old_vert_arr) * (size_t)numVerts, "old_vert_arr in solidify");
241 unsigned int *edge_users = NULL;
242 char *edge_order = NULL;
244 float (*vert_nors)[3] = NULL;
245 float (*face_nors)[3] = NULL;
247 const bool need_face_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) || (smd->flag & MOD_SOLIDIFY_EVEN);
249 const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
250 const float ofs_new = smd->offset + ofs_orig;
251 const float offset_fac_vg = smd->offset_fac_vg;
252 const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
253 const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
254 const bool do_clamp = (smd->offset_clamp != 0.0f);
255 const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == 0;
258 MDeformVert *dvert, *dv = NULL;
259 const int defgrp_invert = ((smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0);
262 /* array size is doubled in case of using a shell */
263 const unsigned int stride = do_shell ? 2 : 1;
265 modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
267 orig_mvert = dm->getVertArray(dm);
268 orig_medge = dm->getEdgeArray(dm);
269 orig_mloop = dm->getLoopArray(dm);
270 orig_mpoly = dm->getPolyArray(dm);
272 if (need_face_normals) {
273 /* calculate only face normals */
274 face_nors = MEM_mallocN(sizeof(*face_nors) * (size_t)numFaces, __func__);
275 BKE_mesh_calc_normals_poly(
276 orig_mvert, (int)numVerts,
277 orig_mloop, orig_mpoly,
278 (int)numLoops, (int)numFaces,
282 STACK_INIT(new_vert_arr, numVerts * 2);
283 STACK_INIT(new_edge_arr, numEdges * 2);
285 if (smd->flag & MOD_SOLIDIFY_RIM) {
286 BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__);
289 #define INVALID_UNUSED ((unsigned int)-1)
290 #define INVALID_PAIR ((unsigned int)-2)
292 new_vert_arr = MEM_mallocN(sizeof(*new_vert_arr) * (size_t)(numVerts * 2), __func__);
293 new_edge_arr = MEM_mallocN(sizeof(*new_edge_arr) * (size_t)((numEdges * 2) + numVerts), __func__);
295 edge_users = MEM_mallocN(sizeof(*edge_users) * (size_t)numEdges, "solid_mod edges");
296 edge_order = MEM_mallocN(sizeof(*edge_order) * (size_t)numEdges, "solid_mod eorder");
299 /* save doing 2 loops here... */
301 fill_vn_i(edge_users, numEdges, INVALID_UNUSED);
304 for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
305 edge_users[eidx] = INVALID_UNUSED;
308 for (i = 0, mp = orig_mpoly; i < numFaces; i++, mp++) {
312 ml = orig_mloop + mp->loopstart;
313 ml_prev = ml + (mp->totloop - 1);
315 for (j = 0; j < mp->totloop; j++, ml++) {
318 if (edge_users[eidx] == INVALID_UNUSED) {
319 ed = orig_medge + eidx;
320 BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) &&
321 ELEM(ml->v, ed->v1, ed->v2));
322 edge_users[eidx] = (ml_prev->v > ml->v) == (ed->v1 < ed->v2) ? i : (i + numFaces);
323 edge_order[eidx] = j;
326 edge_users[eidx] = INVALID_PAIR;
332 for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
333 if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) {
334 BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v1);
335 BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v2);
336 STACK_PUSH(new_edge_arr, eidx);
342 for (i = 0; i < numVerts; i++) {
343 if (BLI_BITMAP_TEST(orig_mvert_tag, i)) {
344 old_vert_arr[i] = STACK_SIZE(new_vert_arr);
345 STACK_PUSH(new_vert_arr, i);
349 old_vert_arr[i] = INVALID_UNUSED;
353 MEM_freeN(orig_mvert_tag);
356 if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
357 vert_nors = MEM_callocN(sizeof(float) * (size_t)numVerts * 3, "mod_solid_vno_hq");
358 dm_calc_normal(dm, face_nors, vert_nors);
361 newVerts = do_shell ? 0 : newEdges;
363 result = CDDM_from_template(dm,
364 (int)((numVerts * stride) + newVerts),
365 (int)((numEdges * stride) + newEdges + newVerts), 0,
366 (int)((numLoops * stride) + newLoops),
367 (int)((numFaces * stride) + newFaces));
369 mpoly = CDDM_get_polys(result);
370 mloop = CDDM_get_loops(result);
371 medge = CDDM_get_edges(result);
372 mvert = CDDM_get_verts(result);
375 DM_copy_vert_data(dm, result, 0, 0, (int)numVerts);
376 DM_copy_vert_data(dm, result, 0, (int)numVerts, (int)numVerts);
378 DM_copy_edge_data(dm, result, 0, 0, (int)numEdges);
379 DM_copy_edge_data(dm, result, 0, (int)numEdges, (int)numEdges);
381 DM_copy_loop_data(dm, result, 0, 0, (int)numLoops);
382 DM_copy_loop_data(dm, result, 0, (int)numLoops, (int)numLoops);
384 DM_copy_poly_data(dm, result, 0, 0, (int)numFaces);
385 DM_copy_poly_data(dm, result, 0, (int)numFaces, (int)numFaces);
389 DM_copy_vert_data(dm, result, 0, 0, (int)numVerts);
390 for (i = 0, j = (int)numVerts; i < numVerts; i++) {
391 if (old_vert_arr[i] != INVALID_UNUSED) {
392 DM_copy_vert_data(dm, result, i, j, 1);
397 DM_copy_edge_data(dm, result, 0, 0, (int)numEdges);
399 for (i = 0, j = (int)numEdges; i < numEdges; i++) {
400 if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) {
401 MEdge* ed_src, *ed_dst;
402 DM_copy_edge_data(dm, result, i, j, 1);
406 ed_dst->v1 = old_vert_arr[ed_src->v1] + numVerts;
407 ed_dst->v2 = old_vert_arr[ed_src->v2] + numVerts;
412 /* will be created later */
413 DM_copy_loop_data(dm, result, 0, 0, (int)numLoops);
414 DM_copy_poly_data(dm, result, 0, 0, (int)numFaces);
417 #undef INVALID_UNUSED
423 mp = mpoly + numFaces;
424 for (i = 0; i < dm->numPolyData; i++, mp++) {
429 ml2 = mloop + mp->loopstart + dm->numLoopData;
430 for (j = 0; j < mp->totloop; j++) {
431 CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j,
432 mp->loopstart + (mp->totloop - j - 1) + dm->numLoopData, 1);
436 mp->mat_nr += mat_ofs;
437 CLAMP(mp->mat_nr, 0, mat_nr_max);
441 for (j = 0; j < mp->totloop - 1; j++) {
442 ml2[j].e = ml2[j + 1].e;
444 ml2[mp->totloop - 1].e = e;
446 mp->loopstart += dm->numLoopData;
448 for (j = 0; j < mp->totloop; j++) {
449 ml2[j].e += numEdges;
450 ml2[j].v += numVerts;
454 for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) {
460 /* note, copied vertex layers don't have flipped normals yet. do this after applying offset */
461 if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) {
462 /* no even thickness, very simple */
464 float scalar_short_vgroup;
467 float *vert_lens = NULL;
468 const float offset = fabsf(smd->offset) * smd->offset_clamp;
469 const float offset_sq = offset * offset;
472 vert_lens = MEM_mallocN(sizeof(float) * numVerts, "vert_lens");
473 fill_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
474 for (i = 0; i < numEdges; i++) {
475 const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
476 vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq);
477 vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len_sq);
481 if (ofs_new != 0.0f) {
483 scalar_short = scalar_short_vgroup = ofs_new / 32767.0f;
485 if ((ofs_new >= ofs_orig) == do_flip) {
486 i_end = do_shell ? numVerts : newVerts;
487 mv = &mvert[numVerts];
495 for (i = 0; i < i_end; i++, mv++) {
497 if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
498 else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
499 scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
503 /* always reset becaise we may have set before */
505 scalar_short_vgroup = scalar_short;
507 if (vert_lens[i] < offset_sq) {
508 float scalar = sqrtf(vert_lens[i]) / offset;
509 scalar_short_vgroup *= scalar;
512 madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
516 if (ofs_orig != 0.0f) {
518 scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f;
520 /* as above but swapped */
521 if ((ofs_new >= ofs_orig) == do_flip) {
526 i_end = do_shell ? numVerts : newVerts;
527 mv = &mvert[numVerts];
531 for (i = 0; i < i_end; i++, mv++) {
533 if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
534 else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
535 scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
539 /* always reset becaise we may have set before */
541 scalar_short_vgroup = scalar_short;
543 if (vert_lens[i] < offset_sq) {
544 float scalar = sqrtf(vert_lens[i]) / offset;
545 scalar_short_vgroup *= scalar;
548 madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
553 MEM_freeN(vert_lens);
557 #ifdef USE_NONMANIFOLD_WORKAROUND
558 const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0;
560 /* same as EM_solidify() in editmesh_lib.c */
561 float *vert_angles = MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */
562 float *vert_accum = vert_angles + numVerts;
565 if (vert_nors == NULL) {
566 vert_nors = MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno");
567 for (i = 0, mv = mvert; i < numVerts; i++, mv++) {
568 normal_short_to_float_v3(vert_nors[i], mv->no);
572 for (i = 0, mp = mpoly; i < numFaces; i++, mp++) {
573 /* #BKE_mesh_calc_poly_angles logic is inlined here */
577 int i_curr = mp->totloop - 1;
580 ml = &mloop[mp->loopstart];
582 sub_v3_v3v3(nor_prev, mvert[ml[i_curr - 1].v].co, mvert[ml[i_curr].v].co);
583 normalize_v3(nor_prev);
585 while (i_next < mp->totloop) {
587 sub_v3_v3v3(nor_next, mvert[ml[i_curr].v].co, mvert[ml[i_next].v].co);
588 normalize_v3(nor_next);
589 angle = angle_normalized_v3v3(nor_prev, nor_next);
592 /* --- not related to angle calc --- */
593 if (angle < FLT_EPSILON) {
598 vert_accum[vidx] += angle;
600 #ifdef USE_NONMANIFOLD_WORKAROUND
601 /* skip 3+ face user edges */
602 if ((check_non_manifold == false) ||
603 LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) &&
604 ((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0)))
606 vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_nors[i]) * angle;
609 vert_angles[vidx] += angle;
612 vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_nors[i]) * angle;
614 /* --- end non-angle-calc section --- */
618 copy_v3_v3(nor_prev, nor_next);
624 /* vertex group support */
630 for (i = 0; i < numVerts; i++, dv++) {
631 scalar = 1.0f - defvert_find_weight(dv, defgrp_index);
632 scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
633 vert_angles[i] *= scalar;
637 for (i = 0; i < numVerts; i++, dv++) {
638 scalar = defvert_find_weight(dv, defgrp_index);
639 scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
640 vert_angles[i] *= scalar;
646 float *vert_lens_sq = MEM_callocN(sizeof(float) * numVerts, "vert_lens");
647 const float offset = fabsf(smd->offset) * smd->offset_clamp;
648 const float offset_sq = offset * offset;
649 fill_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX);
650 for (i = 0; i < numEdges; i++) {
651 const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
652 vert_lens_sq[medge[i].v1] = min_ff(vert_lens_sq[medge[i].v1], ed_len);
653 vert_lens_sq[medge[i].v2] = min_ff(vert_lens_sq[medge[i].v2], ed_len);
655 for (i = 0; i < numVerts; i++) {
656 if (vert_lens_sq[i] < offset_sq) {
657 float scalar = sqrtf(vert_lens_sq[i]) / offset;
658 vert_angles[i] *= scalar;
661 MEM_freeN(vert_lens_sq);
667 if ((ofs_new >= ofs_orig) == do_flip) {
668 i_end = do_shell ? numVerts : newVerts;
676 for (mv = &mvert[i]; i < i_end; i++, mv++) {
677 if (vert_accum[i]) { /* zero if unselected */
678 madd_v3_v3fl(mv->co, vert_nors[i], ofs_new * (vert_angles[i] / vert_accum[i]));
686 /* same as above but swapped, intentional use of 'ofs_new' */
687 if ((ofs_new >= ofs_orig) == do_flip) {
692 i_end = do_shell ? numVerts : newVerts;
696 for (mv = &mvert[i]; i < i_end; i++, mv++) {
697 if (vert_accum[i]) { /* zero if unselected */
698 madd_v3_v3fl(mv->co, vert_nors[i], ofs_orig * (vert_angles[i] / vert_accum[i]));
703 MEM_freeN(vert_angles);
707 MEM_freeN(vert_nors);
709 /* must recalculate normals with vgroups since they can displace unevenly [#26888] */
710 if ((dm->dirty & DM_DIRTY_NORMALS) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) {
711 result->dirty |= DM_DIRTY_NORMALS;
714 /* flip vertex normals for copied verts */
715 mv = mvert + numVerts;
716 for (i = 0; i < numVerts; i++, mv++) {
717 negate_v3_short(mv->no);
721 if (smd->flag & MOD_SOLIDIFY_RIM) {
723 /* bugger, need to re-calculate the normals for the new edge faces.
724 * This could be done in many ways, but probably the quickest way
725 * is to calculate the average normals for side faces only.
726 * Then blend them with the normals of the edge verts.
728 * at the moment its easiest to allocate an entire array for every vertex,
729 * even though we only need edge verts - campbell
732 #define SOLIDIFY_SIDE_NORMALS
734 #ifdef SOLIDIFY_SIDE_NORMALS
735 const bool do_side_normals = !(result->dirty & DM_DIRTY_NORMALS);
736 /* annoying to allocate these since we only need the edge verts, */
737 float (*edge_vert_nos)[3] = do_side_normals ? MEM_callocN(sizeof(float) * numVerts * 3, __func__) : NULL;
740 const unsigned char crease_rim = smd->crease_rim * 255.0f;
741 const unsigned char crease_outer = smd->crease_outer * 255.0f;
742 const unsigned char crease_inner = smd->crease_inner * 255.0f;
748 if (crease_rim || crease_outer || crease_inner) {
749 result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
752 /* add faces & edges */
753 origindex_edge = result->getEdgeDataArray(result, CD_ORIGINDEX);
754 ed = &medge[(numEdges * stride) + newVerts]; /* start after copied edges */
755 orig_ed = &origindex_edge[(numEdges * stride) + newVerts];
756 for (i = 0; i < newEdges; i++, ed++, orig_ed++) {
757 ed->v1 = new_vert_arr[i];
758 ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts;
759 ed->flag |= ME_EDGEDRAW;
761 *orig_ed = ORIGINDEX_NONE;
764 ed->crease = crease_rim;
769 mp = mpoly + (numFaces * stride);
770 ml = mloop + (numLoops * stride);
772 for (i = 0; i < newFaces; i++, mp++) {
773 unsigned int eidx = new_edge_arr[i];
774 unsigned int fidx = edge_users[eidx];
778 if (fidx >= numFaces) {
788 /* copy most of the face settings */
789 DM_copy_poly_data(dm, result, (int)fidx, (int)((numFaces * stride) + i), 1);
790 mp->loopstart = (int)(j + (numLoops * stride));
791 mp->flag = mpoly[fidx].flag;
793 /* notice we use 'mp->totloop' which is later overwritten,
794 * we could lookup the original face but theres no point since this is a copy
795 * and will have the same value, just take care when changing order of assignment */
796 k1 = mpoly[fidx].loopstart + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop); /* prev loop */
797 k2 = mpoly[fidx].loopstart + (edge_order[eidx]);
801 CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 0), 1);
802 CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 1), 1);
803 CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 2), 1);
804 CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 3), 1);
811 ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newVerts;
813 ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
814 ml[j++].e = (do_shell ? eidx : i) + numEdges;
816 ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
817 ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newVerts;
824 ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newVerts;
826 ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
827 ml[j++].e = (do_shell ? eidx : i) + numEdges;
829 ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
830 ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newVerts;
833 origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE;
834 origindex_edge[ml[j - 1].e] = ORIGINDEX_NONE;
836 /* use the next material index if option enabled */
838 mp->mat_nr += mat_ofs_rim;
839 CLAMP(mp->mat_nr, 0, mat_nr_max);
842 /* crease += crease_outer; without wrapping */
843 char *cr = &(ed->crease);
844 int tcr = *cr + crease_outer;
845 *cr = tcr > 255 ? 255 : tcr;
849 /* crease += crease_inner; without wrapping */
850 char *cr = &(medge[numEdges + (do_shell ? eidx : i)].crease);
851 int tcr = *cr + crease_inner;
852 *cr = tcr > 255 ? 255 : tcr;
855 #ifdef SOLIDIFY_SIDE_NORMALS
856 if (do_side_normals) {
858 mvert[ml[j - 4].v].co,
859 mvert[ml[j - 3].v].co,
860 mvert[ml[j - 2].v].co,
861 mvert[ml[j - 1].v].co);
863 add_v3_v3(edge_vert_nos[ed->v1], nor);
864 add_v3_v3(edge_vert_nos[ed->v2], nor);
869 #ifdef SOLIDIFY_SIDE_NORMALS
870 if (do_side_normals) {
871 ed = medge + (numEdges * stride);
872 for (i = 0; i < newEdges; i++, ed++) {
877 /* note, only the first vertex (lower half of the index) is calculated */
878 normalize_v3_v3(nor_cpy, edge_vert_nos[ed->v1]);
880 for (k = 0; k < 2; k++) { /* loop over both verts of the edge */
881 nor_short = mvert[*(&ed->v1 + k)].no;
882 normal_short_to_float_v3(nor, nor_short);
883 add_v3_v3(nor, nor_cpy);
885 normal_float_to_short_v3(nor_short, nor);
889 MEM_freeN(edge_vert_nos);
893 MEM_freeN(new_vert_arr);
894 MEM_freeN(new_edge_arr);
896 MEM_freeN(edge_users);
897 MEM_freeN(edge_order);
901 MEM_freeN(old_vert_arr);
904 MEM_freeN(face_nors);
906 if (numFaces == 0 && numEdges != 0) {
907 modifier_setError(md, "Faces needed for useful output");
913 #undef SOLIDIFY_SIDE_NORMALS
915 static bool dependsOnNormals(ModifierData *UNUSED(md))
917 /* even when we calculate our own normals,
918 * the vertex normals are used as a fallback */
922 ModifierTypeInfo modifierType_Solidify = {
923 /* name */ "Solidify",
924 /* structName */ "SolidifyModifierData",
925 /* structSize */ sizeof(SolidifyModifierData),
926 /* type */ eModifierTypeType_Constructive,
928 /* flags */ eModifierTypeFlag_AcceptsMesh |
929 eModifierTypeFlag_AcceptsCVs |
930 eModifierTypeFlag_SupportsMapping |
931 eModifierTypeFlag_SupportsEditmode |
932 eModifierTypeFlag_EnableInEditmode,
934 /* copyData */ copyData,
935 /* deformVerts */ NULL,
936 /* deformMatrices */ NULL,
937 /* deformVertsEM */ NULL,
938 /* deformMatricesEM */ NULL,
939 /* applyModifier */ applyModifier,
940 /* applyModifierEM */ NULL,
941 /* initData */ initData,
942 /* requiredDataMask */ requiredDataMask,
944 /* isDisabled */ NULL,
945 /* updateDepgraph */ NULL,
946 /* dependsOnTime */ NULL,
947 /* dependsOnNormals */ dependsOnNormals,
948 /* foreachObjectLink */ NULL,
949 /* foreachIDLink */ NULL,
950 /* foreachTexLink */ NULL,