diff options
Diffstat (limited to 'source/blender/modifiers/intern/MOD_solidify.c')
-rw-r--r-- | source/blender/modifiers/intern/MOD_solidify.c | 1696 |
1 files changed, 859 insertions, 837 deletions
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index e8a7d8217ed..9fb2e728dd9 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -50,13 +50,13 @@ /* could be exposed for other functions to use */ typedef struct EdgeFaceRef { - int p1; /* init as -1 */ - int p2; + int p1; /* init as -1 */ + int p2; } EdgeFaceRef; BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref) { - return !((edge_ref->p1 == 0) && (edge_ref->p2 == 0)); + return !((edge_ref->p1 == 0) && (edge_ref->p2 == 0)); } /** @@ -66,912 +66,934 @@ BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref) */ static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_vert_nors)[3]) { - int i, numVerts, numEdges, numPolys; - MPoly *mpoly, *mp; - MLoop *mloop, *ml; - MEdge *medge, *ed; - MVert *mvert, *mv; - - numVerts = mesh->totvert; - numEdges = mesh->totedge; - numPolys = mesh->totpoly; - mpoly = mesh->mpoly; - medge = mesh->medge; - mvert = mesh->mvert; - mloop = mesh->mloop; - - /* we don't want to overwrite any referenced layers */ - - /* Doesn't work here! */ + int i, numVerts, numEdges, numPolys; + MPoly *mpoly, *mp; + MLoop *mloop, *ml; + MEdge *medge, *ed; + MVert *mvert, *mv; + + numVerts = mesh->totvert; + numEdges = mesh->totedge; + numPolys = mesh->totpoly; + mpoly = mesh->mpoly; + medge = mesh->medge; + mvert = mesh->mvert; + mloop = mesh->mloop; + + /* we don't want to overwrite any referenced layers */ + + /* Doesn't work here! */ #if 0 - mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts); - cddm->mvert = mv; + mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts); + cddm->mvert = mv; #endif - mv = mvert; - mp = mpoly; - - { - EdgeFaceRef *edge_ref_array = MEM_calloc_arrayN((size_t)numEdges, sizeof(EdgeFaceRef), "Edge Connectivity"); - EdgeFaceRef *edge_ref; - float edge_normal[3]; - - /* Add an edge reference if it's not there, pointing back to the face index. */ - for (i = 0; i < numPolys; i++, mp++) { - int j; - - ml = mloop + mp->loopstart; - - for (j = 0; j < mp->totloop; j++, ml++) { - /* --- add edge ref to face --- */ - edge_ref = &edge_ref_array[ml->e]; - if (!edgeref_is_init(edge_ref)) { - edge_ref->p1 = i; - edge_ref->p2 = -1; - } - else if ((edge_ref->p1 != -1) && (edge_ref->p2 == -1)) { - edge_ref->p2 = i; - } - else { - /* 3+ faces using an edge, we can't handle this usefully */ - edge_ref->p1 = edge_ref->p2 = -1; + mv = mvert; + mp = mpoly; + + { + EdgeFaceRef *edge_ref_array = MEM_calloc_arrayN( + (size_t)numEdges, sizeof(EdgeFaceRef), "Edge Connectivity"); + EdgeFaceRef *edge_ref; + float edge_normal[3]; + + /* Add an edge reference if it's not there, pointing back to the face index. */ + for (i = 0; i < numPolys; i++, mp++) { + int j; + + ml = mloop + mp->loopstart; + + for (j = 0; j < mp->totloop; j++, ml++) { + /* --- add edge ref to face --- */ + edge_ref = &edge_ref_array[ml->e]; + if (!edgeref_is_init(edge_ref)) { + edge_ref->p1 = i; + edge_ref->p2 = -1; + } + else if ((edge_ref->p1 != -1) && (edge_ref->p2 == -1)) { + edge_ref->p2 = i; + } + else { + /* 3+ faces using an edge, we can't handle this usefully */ + edge_ref->p1 = edge_ref->p2 = -1; #ifdef USE_NONMANIFOLD_WORKAROUND - medge[ml->e].flag |= ME_EDGE_TMP_TAG; + medge[ml->e].flag |= ME_EDGE_TMP_TAG; #endif - } - /* --- done --- */ - } - } - - for (i = 0, ed = medge, edge_ref = edge_ref_array; i < numEdges; i++, ed++, edge_ref++) { - /* Get the edge vert indices, and edge value (the face indices that use it) */ - - if (edgeref_is_init(edge_ref) && (edge_ref->p1 != -1)) { - if (edge_ref->p2 != -1) { - /* We have 2 faces using this edge, calculate the edges normal - * using the angle between the 2 faces as a weighting */ + } + /* --- done --- */ + } + } + + for (i = 0, ed = medge, edge_ref = edge_ref_array; i < numEdges; i++, ed++, edge_ref++) { + /* Get the edge vert indices, and edge value (the face indices that use it) */ + + if (edgeref_is_init(edge_ref) && (edge_ref->p1 != -1)) { + if (edge_ref->p2 != -1) { + /* We have 2 faces using this edge, calculate the edges normal + * using the angle between the 2 faces as a weighting */ #if 0 - add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]); - normalize_v3_length( - edge_normal, - angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2])); + add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]); + normalize_v3_length( + edge_normal, + angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2])); #else - mid_v3_v3v3_angle_weighted(edge_normal, poly_nors[edge_ref->p1], poly_nors[edge_ref->p2]); + mid_v3_v3v3_angle_weighted( + edge_normal, poly_nors[edge_ref->p1], poly_nors[edge_ref->p2]); #endif - } - else { - /* only one face attached to that edge */ - /* an edge without another attached- the weight on this is undefined */ - copy_v3_v3(edge_normal, poly_nors[edge_ref->p1]); - } - add_v3_v3(r_vert_nors[ed->v1], edge_normal); - add_v3_v3(r_vert_nors[ed->v2], edge_normal); - } - } - MEM_freeN(edge_ref_array); - } - - /* normalize vertex normals and assign */ - for (i = 0; i < numVerts; i++, mv++) { - if (normalize_v3(r_vert_nors[i]) == 0.0f) { - normal_short_to_float_v3(r_vert_nors[i], mv->no); - } - } + } + else { + /* only one face attached to that edge */ + /* an edge without another attached- the weight on this is undefined */ + copy_v3_v3(edge_normal, poly_nors[edge_ref->p1]); + } + add_v3_v3(r_vert_nors[ed->v1], edge_normal); + add_v3_v3(r_vert_nors[ed->v2], edge_normal); + } + } + MEM_freeN(edge_ref_array); + } + + /* normalize vertex normals and assign */ + for (i = 0; i < numVerts; i++, mv++) { + if (normalize_v3(r_vert_nors[i]) == 0.0f) { + normal_short_to_float_v3(r_vert_nors[i], mv->no); + } + } } static void initData(ModifierData *md) { - SolidifyModifierData *smd = (SolidifyModifierData *) md; - smd->offset = 0.01f; - smd->offset_fac = -1.0f; - smd->flag = MOD_SOLIDIFY_RIM; + SolidifyModifierData *smd = (SolidifyModifierData *)md; + smd->offset = 0.01f; + smd->offset_fac = -1.0f; + smd->flag = MOD_SOLIDIFY_RIM; } -static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *md, + CustomData_MeshMasks *r_cddata_masks) { - SolidifyModifierData *smd = (SolidifyModifierData *) md; + SolidifyModifierData *smd = (SolidifyModifierData *)md; - /* ask for vertexgroups if we need them */ - if (smd->defgrp_name[0] != '\0') { - r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; - } + /* ask for vertexgroups if we need them */ + if (smd->defgrp_name[0] != '\0') { + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + } } /* specific function for solidify - define locally */ BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f) { - r[0] += (float)a[0] * f; - r[1] += (float)a[1] * f; - r[2] += (float)a[2] * f; + r[0] += (float)a[0] * f; + r[1] += (float)a[1] * f; + r[2] += (float)a[2] * f; } -static Mesh *applyModifier( - ModifierData *md, const ModifierEvalContext *ctx, - Mesh *mesh) +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { - Mesh *result; - const SolidifyModifierData *smd = (SolidifyModifierData *) md; - - MVert *mv, *mvert, *orig_mvert; - MEdge *ed, *medge, *orig_medge; - MLoop *ml, *mloop, *orig_mloop; - MPoly *mp, *mpoly, *orig_mpoly; - const unsigned int numVerts = (unsigned int)mesh->totvert; - const unsigned int numEdges = (unsigned int)mesh->totedge; - const unsigned int numPolys = (unsigned int)mesh->totpoly; - const unsigned int numLoops = (unsigned int)mesh->totloop; - unsigned int newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0; - - /* only use material offsets if we have 2 or more materials */ - const short mat_nr_max = ctx->object->totcol > 1 ? ctx->object->totcol - 1 : 0; - const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0; - const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0; - - /* use for edges */ - /* over-alloc new_vert_arr, old_vert_arr */ - unsigned int *new_vert_arr = NULL; - STACK_DECLARE(new_vert_arr); - - unsigned int *new_edge_arr = NULL; - STACK_DECLARE(new_edge_arr); - - unsigned int *old_vert_arr = MEM_calloc_arrayN(numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify"); - - unsigned int *edge_users = NULL; - char *edge_order = NULL; - - float (*vert_nors)[3] = NULL; - float (*poly_nors)[3] = NULL; - - const bool need_poly_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) || (smd->flag & MOD_SOLIDIFY_EVEN); - - const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset); - const float ofs_new = smd->offset + ofs_orig; - const float offset_fac_vg = smd->offset_fac_vg; - const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg; - const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0; - const bool do_clamp = (smd->offset_clamp != 0.0f); - const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == 0; - - /* weights */ - MDeformVert *dvert; - const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0; - int defgrp_index; - - /* array size is doubled in case of using a shell */ - const unsigned int stride = do_shell ? 2 : 1; - - MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index); - - orig_mvert = mesh->mvert; - orig_medge = mesh->medge; - orig_mloop = mesh->mloop; - orig_mpoly = mesh->mpoly; - - if (need_poly_normals) { - /* calculate only face normals */ - poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__); - BKE_mesh_calc_normals_poly( - orig_mvert, NULL, (int)numVerts, - orig_mloop, orig_mpoly, - (int)numLoops, (int)numPolys, - poly_nors, true); - } - - STACK_INIT(new_vert_arr, numVerts * 2); - STACK_INIT(new_edge_arr, numEdges * 2); - - if (smd->flag & MOD_SOLIDIFY_RIM) { - BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__); - unsigned int eidx; - unsigned int i; + Mesh *result; + const SolidifyModifierData *smd = (SolidifyModifierData *)md; + + MVert *mv, *mvert, *orig_mvert; + MEdge *ed, *medge, *orig_medge; + MLoop *ml, *mloop, *orig_mloop; + MPoly *mp, *mpoly, *orig_mpoly; + const unsigned int numVerts = (unsigned int)mesh->totvert; + const unsigned int numEdges = (unsigned int)mesh->totedge; + const unsigned int numPolys = (unsigned int)mesh->totpoly; + const unsigned int numLoops = (unsigned int)mesh->totloop; + unsigned int newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0; + + /* only use material offsets if we have 2 or more materials */ + const short mat_nr_max = ctx->object->totcol > 1 ? ctx->object->totcol - 1 : 0; + const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0; + const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0; + + /* use for edges */ + /* over-alloc new_vert_arr, old_vert_arr */ + unsigned int *new_vert_arr = NULL; + STACK_DECLARE(new_vert_arr); + + unsigned int *new_edge_arr = NULL; + STACK_DECLARE(new_edge_arr); + + unsigned int *old_vert_arr = MEM_calloc_arrayN( + numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify"); + + unsigned int *edge_users = NULL; + char *edge_order = NULL; + + float(*vert_nors)[3] = NULL; + float(*poly_nors)[3] = NULL; + + const bool need_poly_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) || + (smd->flag & MOD_SOLIDIFY_EVEN); + + const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset); + const float ofs_new = smd->offset + ofs_orig; + const float offset_fac_vg = smd->offset_fac_vg; + const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg; + const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0; + const bool do_clamp = (smd->offset_clamp != 0.0f); + const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == + 0; + + /* weights */ + MDeformVert *dvert; + const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0; + int defgrp_index; + + /* array size is doubled in case of using a shell */ + const unsigned int stride = do_shell ? 2 : 1; + + MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index); + + orig_mvert = mesh->mvert; + orig_medge = mesh->medge; + orig_mloop = mesh->mloop; + orig_mpoly = mesh->mpoly; + + if (need_poly_normals) { + /* calculate only face normals */ + poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__); + BKE_mesh_calc_normals_poly(orig_mvert, + NULL, + (int)numVerts, + orig_mloop, + orig_mpoly, + (int)numLoops, + (int)numPolys, + poly_nors, + true); + } + + STACK_INIT(new_vert_arr, numVerts * 2); + STACK_INIT(new_edge_arr, numEdges * 2); + + if (smd->flag & MOD_SOLIDIFY_RIM) { + BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__); + unsigned int eidx; + unsigned int i; #define INVALID_UNUSED ((unsigned int)-1) #define INVALID_PAIR ((unsigned int)-2) - new_vert_arr = MEM_malloc_arrayN(numVerts, 2 * sizeof(*new_vert_arr), __func__); - new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__); + new_vert_arr = MEM_malloc_arrayN(numVerts, 2 * sizeof(*new_vert_arr), __func__); + new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__); - edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges"); - edge_order = MEM_malloc_arrayN(numEdges, sizeof(*edge_order), "solid_mod eorder"); + edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges"); + edge_order = MEM_malloc_arrayN(numEdges, sizeof(*edge_order), "solid_mod eorder"); - - /* save doing 2 loops here... */ + /* save doing 2 loops here... */ #if 0 - copy_vn_i(edge_users, numEdges, INVALID_UNUSED); + copy_vn_i(edge_users, numEdges, INVALID_UNUSED); #endif - for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) { - edge_users[eidx] = INVALID_UNUSED; - } - - for (i = 0, mp = orig_mpoly; i < numPolys; i++, mp++) { - MLoop *ml_prev; - int j; - - ml = orig_mloop + mp->loopstart; - ml_prev = ml + (mp->totloop - 1); - - for (j = 0; j < mp->totloop; j++, ml++) { - /* add edge user */ - eidx = ml_prev->e; - if (edge_users[eidx] == INVALID_UNUSED) { - ed = orig_medge + eidx; - BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && - ELEM(ml->v, ed->v1, ed->v2)); - edge_users[eidx] = (ml_prev->v > ml->v) == (ed->v1 < ed->v2) ? i : (i + numPolys); - edge_order[eidx] = j; - } - else { - edge_users[eidx] = INVALID_PAIR; - } - ml_prev = ml; - } - } - - for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) { - if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) { - BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v1); - BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v2); - STACK_PUSH(new_edge_arr, eidx); - newPolys++; - newLoops += 4; - } - } - - for (i = 0; i < numVerts; i++) { - if (BLI_BITMAP_TEST(orig_mvert_tag, i)) { - old_vert_arr[i] = STACK_SIZE(new_vert_arr); - STACK_PUSH(new_vert_arr, i); - rimVerts++; - } - else { - old_vert_arr[i] = INVALID_UNUSED; - } - } - - MEM_freeN(orig_mvert_tag); - } - - if (do_shell == false) { - /* only add rim vertices */ - newVerts = rimVerts; - /* each extruded face needs an opposite edge */ - newEdges = newPolys; - } - else { - /* (stride == 2) in this case, so no need to add newVerts/newEdges */ - BLI_assert(newVerts == 0); - BLI_assert(newEdges == 0); - } - - if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) { - vert_nors = MEM_calloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno_hq"); - mesh_calc_hq_normal(mesh, poly_nors, vert_nors); - } - - result = BKE_mesh_new_nomain_from_template( - mesh, - (int)((numVerts * stride) + newVerts), - (int)((numEdges * stride) + newEdges + rimVerts), 0, - (int)((numLoops * stride) + newLoops), - (int)((numPolys * stride) + newPolys)); - - mpoly = result->mpoly; - mloop = result->mloop; - medge = result->medge; - mvert = result->mvert; - - if (do_shell) { - CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts); - CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)numVerts, (int)numVerts); - - CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges); - CustomData_copy_data(&mesh->edata, &result->edata, 0, (int)numEdges, (int)numEdges); - - CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops); - /* DO NOT copy here the 'copied' part of loop data, we want to reverse loops - * (so that winding of copied face get reversed, so that normals get reversed - * and point in expected direction...). - * If we also copy data here, then this data get overwritten (and allocated memory becomes memleak). */ - - CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys); - CustomData_copy_data(&mesh->pdata, &result->pdata, 0, (int)numPolys, (int)numPolys); - } - else { - int i, j; - CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts); - for (i = 0, j = (int)numVerts; i < numVerts; i++) { - if (old_vert_arr[i] != INVALID_UNUSED) { - CustomData_copy_data(&mesh->vdata, &result->vdata, i, j, 1); - j++; - } - } - - CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges); - - for (i = 0, j = (int)numEdges; i < numEdges; i++) { - if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) { - MEdge *ed_src, *ed_dst; - CustomData_copy_data(&mesh->edata, &result->edata, i, j, 1); - - ed_src = &medge[i]; - ed_dst = &medge[j]; - ed_dst->v1 = old_vert_arr[ed_src->v1] + numVerts; - ed_dst->v2 = old_vert_arr[ed_src->v2] + numVerts; - j++; - } - } - - /* will be created later */ - CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops); - CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys); - } + for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) { + edge_users[eidx] = INVALID_UNUSED; + } + + for (i = 0, mp = orig_mpoly; i < numPolys; i++, mp++) { + MLoop *ml_prev; + int j; + + ml = orig_mloop + mp->loopstart; + ml_prev = ml + (mp->totloop - 1); + + for (j = 0; j < mp->totloop; j++, ml++) { + /* add edge user */ + eidx = ml_prev->e; + if (edge_users[eidx] == INVALID_UNUSED) { + ed = orig_medge + eidx; + BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2)); + edge_users[eidx] = (ml_prev->v > ml->v) == (ed->v1 < ed->v2) ? i : (i + numPolys); + edge_order[eidx] = j; + } + else { + edge_users[eidx] = INVALID_PAIR; + } + ml_prev = ml; + } + } + + for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) { + if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) { + BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v1); + BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v2); + STACK_PUSH(new_edge_arr, eidx); + newPolys++; + newLoops += 4; + } + } + + for (i = 0; i < numVerts; i++) { + if (BLI_BITMAP_TEST(orig_mvert_tag, i)) { + old_vert_arr[i] = STACK_SIZE(new_vert_arr); + STACK_PUSH(new_vert_arr, i); + rimVerts++; + } + else { + old_vert_arr[i] = INVALID_UNUSED; + } + } + + MEM_freeN(orig_mvert_tag); + } + + if (do_shell == false) { + /* only add rim vertices */ + newVerts = rimVerts; + /* each extruded face needs an opposite edge */ + newEdges = newPolys; + } + else { + /* (stride == 2) in this case, so no need to add newVerts/newEdges */ + BLI_assert(newVerts == 0); + BLI_assert(newEdges == 0); + } + + if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) { + vert_nors = MEM_calloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno_hq"); + mesh_calc_hq_normal(mesh, poly_nors, vert_nors); + } + + result = BKE_mesh_new_nomain_from_template(mesh, + (int)((numVerts * stride) + newVerts), + (int)((numEdges * stride) + newEdges + rimVerts), + 0, + (int)((numLoops * stride) + newLoops), + (int)((numPolys * stride) + newPolys)); + + mpoly = result->mpoly; + mloop = result->mloop; + medge = result->medge; + mvert = result->mvert; + + if (do_shell) { + CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts); + CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)numVerts, (int)numVerts); + + CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges); + CustomData_copy_data(&mesh->edata, &result->edata, 0, (int)numEdges, (int)numEdges); + + CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops); + /* DO NOT copy here the 'copied' part of loop data, we want to reverse loops + * (so that winding of copied face get reversed, so that normals get reversed + * and point in expected direction...). + * If we also copy data here, then this data get overwritten (and allocated memory becomes memleak). */ + + CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys); + CustomData_copy_data(&mesh->pdata, &result->pdata, 0, (int)numPolys, (int)numPolys); + } + else { + int i, j; + CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts); + for (i = 0, j = (int)numVerts; i < numVerts; i++) { + if (old_vert_arr[i] != INVALID_UNUSED) { + CustomData_copy_data(&mesh->vdata, &result->vdata, i, j, 1); + j++; + } + } + + CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges); + + for (i = 0, j = (int)numEdges; i < numEdges; i++) { + if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) { + MEdge *ed_src, *ed_dst; + CustomData_copy_data(&mesh->edata, &result->edata, i, j, 1); + + ed_src = &medge[i]; + ed_dst = &medge[j]; + ed_dst->v1 = old_vert_arr[ed_src->v1] + numVerts; + ed_dst->v2 = old_vert_arr[ed_src->v2] + numVerts; + j++; + } + } + + /* will be created later */ + CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops); + CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys); + } #undef INVALID_UNUSED #undef INVALID_PAIR - - /* initializes: (i_end, do_shell_align, mv) */ + /* initializes: (i_end, do_shell_align, mv) */ #define INIT_VERT_ARRAY_OFFSETS(test) \ - if (((ofs_new >= ofs_orig) == do_flip) == test) { \ - i_end = numVerts; \ - do_shell_align = true; \ - mv = mvert; \ - } \ - else { \ - if (do_shell) { \ - i_end = numVerts; \ - do_shell_align = true; \ - } \ - else { \ - i_end = newVerts ; \ - do_shell_align = false; \ - } \ - mv = &mvert[numVerts]; \ - } (void)0 - - - /* flip normals */ - - if (do_shell) { - unsigned int i; - - mp = mpoly + numPolys; - for (i = 0; i < mesh->totpoly; i++, mp++) { - const int loop_end = mp->totloop - 1; - MLoop *ml2; - unsigned int e; - int j; - - /* reverses the loop direction (MLoop.v as well as custom-data) - * MLoop.e also needs to be corrected too, done in a separate loop below. */ - ml2 = mloop + mp->loopstart + mesh->totloop; + if (((ofs_new >= ofs_orig) == do_flip) == test) { \ + i_end = numVerts; \ + do_shell_align = true; \ + mv = mvert; \ + } \ + else { \ + if (do_shell) { \ + i_end = numVerts; \ + do_shell_align = true; \ + } \ + else { \ + i_end = newVerts; \ + do_shell_align = false; \ + } \ + mv = &mvert[numVerts]; \ + } \ + (void)0 + + /* flip normals */ + + if (do_shell) { + unsigned int i; + + mp = mpoly + numPolys; + for (i = 0; i < mesh->totpoly; i++, mp++) { + const int loop_end = mp->totloop - 1; + MLoop *ml2; + unsigned int e; + int j; + + /* reverses the loop direction (MLoop.v as well as custom-data) + * MLoop.e also needs to be corrected too, done in a separate loop below. */ + ml2 = mloop + mp->loopstart + mesh->totloop; #if 0 - for (j = 0; j < mp->totloop; j++) { - CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart + j, - mp->loopstart + (loop_end - j) + mesh->totloop, 1); - } + for (j = 0; j < mp->totloop; j++) { + CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart + j, + mp->loopstart + (loop_end - j) + mesh->totloop, 1); + } #else - /* slightly more involved, keep the first vertex the same for the copy, - * ensures the diagonals in the new face match the original. */ - j = 0; - for (int j_prev = loop_end; j < mp->totloop; j_prev = j++) { - CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart + j, - mp->loopstart + (loop_end - j_prev) + mesh->totloop, 1); - } + /* slightly more involved, keep the first vertex the same for the copy, + * ensures the diagonals in the new face match the original. */ + j = 0; + for (int j_prev = loop_end; j < mp->totloop; j_prev = j++) { + CustomData_copy_data(&mesh->ldata, + &result->ldata, + mp->loopstart + j, + mp->loopstart + (loop_end - j_prev) + mesh->totloop, + 1); + } #endif - if (mat_ofs) { - mp->mat_nr += mat_ofs; - CLAMP(mp->mat_nr, 0, mat_nr_max); - } - - e = ml2[0].e; - for (j = 0; j < loop_end; j++) { - ml2[j].e = ml2[j + 1].e; - } - ml2[loop_end].e = e; - - mp->loopstart += mesh->totloop; - - for (j = 0; j < mp->totloop; j++) { - ml2[j].e += numEdges; - ml2[j].v += numVerts; - } - } - - for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) { - ed->v1 += numVerts; - ed->v2 += numVerts; - } - } - - /* note, copied vertex layers don't have flipped normals yet. do this after applying offset */ - if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) { - /* no even thickness, very simple */ - float scalar_short; - float scalar_short_vgroup; - - /* for clamping */ - float *vert_lens = NULL; - const float offset = fabsf(smd->offset) * smd->offset_clamp; - const float offset_sq = offset * offset; - - if (do_clamp) { - unsigned int i; - - vert_lens = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens"); - copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX); - for (i = 0; i < numEdges; i++) { - const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co); - vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq); - vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len_sq); - } - } - - if (ofs_new != 0.0f) { - unsigned int i_orig, i_end; - bool do_shell_align; - - scalar_short = scalar_short_vgroup = ofs_new / 32767.0f; - - INIT_VERT_ARRAY_OFFSETS(false); - - for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { - const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; - if (dvert) { - MDeformVert *dv = &dvert[i]; - if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index); - else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index); - scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short; - } - if (do_clamp) { - /* always reset becaise we may have set before */ - if (dvert == NULL) { - scalar_short_vgroup = scalar_short; - } - if (vert_lens[i] < offset_sq) { - float scalar = sqrtf(vert_lens[i]) / offset; - scalar_short_vgroup *= scalar; - } - } - madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup); - } - } - - if (ofs_orig != 0.0f) { - unsigned int i_orig, i_end; - bool do_shell_align; - - scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f; - - /* as above but swapped */ - INIT_VERT_ARRAY_OFFSETS(true); - - for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { - const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; - if (dvert) { - MDeformVert *dv = &dvert[i]; - if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index); - else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index); - scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short; - } - if (do_clamp) { - /* always reset becaise we may have set before */ - if (dvert == NULL) { - scalar_short_vgroup = scalar_short; - } - if (vert_lens[i] < offset_sq) { - float scalar = sqrtf(vert_lens[i]) / offset; - scalar_short_vgroup *= scalar; - } - } - madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup); - } - } - - if (do_clamp) { - MEM_freeN(vert_lens); - } - } - else { + if (mat_ofs) { + mp->mat_nr += mat_ofs; + CLAMP(mp->mat_nr, 0, mat_nr_max); + } + + e = ml2[0].e; + for (j = 0; j < loop_end; j++) { + ml2[j].e = ml2[j + 1].e; + } + ml2[loop_end].e = e; + + mp->loopstart += mesh->totloop; + + for (j = 0; j < mp->totloop; j++) { + ml2[j].e += numEdges; + ml2[j].v += numVerts; + } + } + + for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) { + ed->v1 += numVerts; + ed->v2 += numVerts; + } + } + + /* note, copied vertex layers don't have flipped normals yet. do this after applying offset */ + if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) { + /* no even thickness, very simple */ + float scalar_short; + float scalar_short_vgroup; + + /* for clamping */ + float *vert_lens = NULL; + const float offset = fabsf(smd->offset) * smd->offset_clamp; + const float offset_sq = offset * offset; + + if (do_clamp) { + unsigned int i; + + vert_lens = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens"); + copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX); + for (i = 0; i < numEdges; i++) { + const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co); + vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq); + vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len_sq); + } + } + + if (ofs_new != 0.0f) { + unsigned int i_orig, i_end; + bool do_shell_align; + + scalar_short = scalar_short_vgroup = ofs_new / 32767.0f; + + INIT_VERT_ARRAY_OFFSETS(false); + + for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { + const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; + if (dvert) { + MDeformVert *dv = &dvert[i]; + if (defgrp_invert) + scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index); + else + scalar_short_vgroup = defvert_find_weight(dv, defgrp_index); + scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * + scalar_short; + } + if (do_clamp) { + /* always reset becaise we may have set before */ + if (dvert == NULL) { + scalar_short_vgroup = scalar_short; + } + if (vert_lens[i] < offset_sq) { + float scalar = sqrtf(vert_lens[i]) / offset; + scalar_short_vgroup *= scalar; + } + } + madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup); + } + } + + if (ofs_orig != 0.0f) { + unsigned int i_orig, i_end; + bool do_shell_align; + + scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f; + + /* as above but swapped */ + INIT_VERT_ARRAY_OFFSETS(true); + + for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { + const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; + if (dvert) { + MDeformVert *dv = &dvert[i]; + if (defgrp_invert) + scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index); + else + scalar_short_vgroup = defvert_find_weight(dv, defgrp_index); + scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * + scalar_short; + } + if (do_clamp) { + /* always reset becaise we may have set before */ + if (dvert == NULL) { + scalar_short_vgroup = scalar_short; + } + if (vert_lens[i] < offset_sq) { + float scalar = sqrtf(vert_lens[i]) / offset; + scalar_short_vgroup *= scalar; + } + } + madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup); + } + } + + if (do_clamp) { + MEM_freeN(vert_lens); + } + } + else { #ifdef USE_NONMANIFOLD_WORKAROUND - const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0; + const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0; #endif - /* same as EM_solidify() in editmesh_lib.c */ - float *vert_angles = MEM_calloc_arrayN(numVerts, 2 * sizeof(float), "mod_solid_pair"); /* 2 in 1 */ - float *vert_accum = vert_angles + numVerts; - unsigned int vidx; - unsigned int i; - - if (vert_nors == NULL) { - vert_nors = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno"); - for (i = 0, mv = mvert; i < numVerts; i++, mv++) { - normal_short_to_float_v3(vert_nors[i], mv->no); - } - } - - for (i = 0, mp = mpoly; i < numPolys; i++, mp++) { - /* #BKE_mesh_calc_poly_angles logic is inlined here */ - float nor_prev[3]; - float nor_next[3]; - - int i_curr = mp->totloop - 1; - int i_next = 0; - - ml = &mloop[mp->loopstart]; - - sub_v3_v3v3(nor_prev, mvert[ml[i_curr - 1].v].co, mvert[ml[i_curr].v].co); - normalize_v3(nor_prev); - - while (i_next < mp->totloop) { - float angle; - sub_v3_v3v3(nor_next, mvert[ml[i_curr].v].co, mvert[ml[i_next].v].co); - normalize_v3(nor_next); - angle = angle_normalized_v3v3(nor_prev, nor_next); - - - /* --- not related to angle calc --- */ - if (angle < FLT_EPSILON) { - angle = FLT_EPSILON; - } - - vidx = ml[i_curr].v; - vert_accum[vidx] += angle; + /* same as EM_solidify() in editmesh_lib.c */ + float *vert_angles = MEM_calloc_arrayN( + numVerts, 2 * sizeof(float), "mod_solid_pair"); /* 2 in 1 */ + float *vert_accum = vert_angles + numVerts; + unsigned int vidx; + unsigned int i; + + if (vert_nors == NULL) { + vert_nors = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno"); + for (i = 0, mv = mvert; i < numVerts; i++, mv++) { + normal_short_to_float_v3(vert_nors[i], mv->no); + } + } + + for (i = 0, mp = mpoly; i < numPolys; i++, mp++) { + /* #BKE_mesh_calc_poly_angles logic is inlined here */ + float nor_prev[3]; + float nor_next[3]; + + int i_curr = mp->totloop - 1; + int i_next = 0; + + ml = &mloop[mp->loopstart]; + + sub_v3_v3v3(nor_prev, mvert[ml[i_curr - 1].v].co, mvert[ml[i_curr].v].co); + normalize_v3(nor_prev); + + while (i_next < mp->totloop) { + float angle; + sub_v3_v3v3(nor_next, mvert[ml[i_curr].v].co, mvert[ml[i_next].v].co); + normalize_v3(nor_next); + angle = angle_normalized_v3v3(nor_prev, nor_next); + + /* --- not related to angle calc --- */ + if (angle < FLT_EPSILON) { + angle = FLT_EPSILON; + } + + vidx = ml[i_curr].v; + vert_accum[vidx] += angle; #ifdef USE_NONMANIFOLD_WORKAROUND - /* skip 3+ face user edges */ - if ((check_non_manifold == false) || - LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) && - ((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0))) - { - vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) * angle; - } - else { - vert_angles[vidx] += angle; - } + /* skip 3+ face user edges */ + if ((check_non_manifold == false) || + LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) && + ((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0))) { + vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) * + angle; + } + else { + vert_angles[vidx] += angle; + } #else - vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) * angle; + vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) * angle; #endif - /* --- end non-angle-calc section --- */ - - - /* step */ - copy_v3_v3(nor_prev, nor_next); - i_curr = i_next; - i_next++; - } - } - - /* vertex group support */ - if (dvert) { - MDeformVert *dv = dvert; - float scalar; - - if (defgrp_invert) { - for (i = 0; i < numVerts; i++, dv++) { - scalar = 1.0f - defvert_find_weight(dv, defgrp_index); - scalar = offset_fac_vg + (scalar * offset_fac_vg_inv); - vert_angles[i] *= scalar; - } - } - else { - for (i = 0; i < numVerts; i++, dv++) { - scalar = defvert_find_weight(dv, defgrp_index); - scalar = offset_fac_vg + (scalar * offset_fac_vg_inv); - vert_angles[i] *= scalar; - } - } - } - - if (do_clamp) { - float *vert_lens_sq = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens"); - const float offset = fabsf(smd->offset) * smd->offset_clamp; - const float offset_sq = offset * offset; - copy_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX); - for (i = 0; i < numEdges; i++) { - const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co); - vert_lens_sq[medge[i].v1] = min_ff(vert_lens_sq[medge[i].v1], ed_len); - vert_lens_sq[medge[i].v2] = min_ff(vert_lens_sq[medge[i].v2], ed_len); - } - for (i = 0; i < numVerts; i++) { - if (vert_lens_sq[i] < offset_sq) { - float scalar = sqrtf(vert_lens_sq[i]) / offset; - vert_angles[i] *= scalar; - } - } - MEM_freeN(vert_lens_sq); - } - - if (ofs_new != 0.0f) { - unsigned int i_orig, i_end; - bool do_shell_align; - - INIT_VERT_ARRAY_OFFSETS(false); - - for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { - const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; - if (vert_accum[i_other]) { /* zero if unselected */ - madd_v3_v3fl(mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other])); - } - } - } - - if (ofs_orig != 0.0f) { - unsigned int i_orig, i_end; - bool do_shell_align; - - /* same as above but swapped, intentional use of 'ofs_new' */ - INIT_VERT_ARRAY_OFFSETS(true); - - for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { - const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; - if (vert_accum[i_other]) { /* zero if unselected */ - madd_v3_v3fl(mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other])); - } - } - } - - MEM_freeN(vert_angles); - } - - if (vert_nors) - MEM_freeN(vert_nors); - - /* must recalculate normals with vgroups since they can displace unevenly [#26888] */ - if ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) { - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - } - else if (do_shell) { - unsigned int i; - /* flip vertex normals for copied verts */ - mv = mvert + numVerts; - for (i = 0; i < numVerts; i++, mv++) { - negate_v3_short(mv->no); - } - } - - if (smd->flag & MOD_SOLIDIFY_RIM) { - unsigned int i; - - /* bugger, need to re-calculate the normals for the new edge faces. - * This could be done in many ways, but probably the quickest way - * is to calculate the average normals for side faces only. - * Then blend them with the normals of the edge verts. - * - * at the moment its easiest to allocate an entire array for every vertex, - * even though we only need edge verts - campbell - */ + /* --- end non-angle-calc section --- */ + + /* step */ + copy_v3_v3(nor_prev, nor_next); + i_curr = i_next; + i_next++; + } + } + + /* vertex group support */ + if (dvert) { + MDeformVert *dv = dvert; + float scalar; + + if (defgrp_invert) { + for (i = 0; i < numVerts; i++, dv++) { + scalar = 1.0f - defvert_find_weight(dv, defgrp_index); + scalar = offset_fac_vg + (scalar * offset_fac_vg_inv); + vert_angles[i] *= scalar; + } + } + else { + for (i = 0; i < numVerts; i++, dv++) { + scalar = defvert_find_weight(dv, defgrp_index); + scalar = offset_fac_vg + (scalar * offset_fac_vg_inv); + vert_angles[i] *= scalar; + } + } + } + + if (do_clamp) { + float *vert_lens_sq = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens"); + const float offset = fabsf(smd->offset) * smd->offset_clamp; + const float offset_sq = offset * offset; + copy_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX); + for (i = 0; i < numEdges; i++) { + const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co); + vert_lens_sq[medge[i].v1] = min_ff(vert_lens_sq[medge[i].v1], ed_len); + vert_lens_sq[medge[i].v2] = min_ff(vert_lens_sq[medge[i].v2], ed_len); + } + for (i = 0; i < numVerts; i++) { + if (vert_lens_sq[i] < offset_sq) { + float scalar = sqrtf(vert_lens_sq[i]) / offset; + vert_angles[i] *= scalar; + } + } + MEM_freeN(vert_lens_sq); + } + + if (ofs_new != 0.0f) { + unsigned int i_orig, i_end; + bool do_shell_align; + + INIT_VERT_ARRAY_OFFSETS(false); + + for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { + const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; + if (vert_accum[i_other]) { /* zero if unselected */ + madd_v3_v3fl( + mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other])); + } + } + } + + if (ofs_orig != 0.0f) { + unsigned int i_orig, i_end; + bool do_shell_align; + + /* same as above but swapped, intentional use of 'ofs_new' */ + INIT_VERT_ARRAY_OFFSETS(true); + + for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { + const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; + if (vert_accum[i_other]) { /* zero if unselected */ + madd_v3_v3fl( + mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other])); + } + } + } + + MEM_freeN(vert_angles); + } + + if (vert_nors) + MEM_freeN(vert_nors); + + /* must recalculate normals with vgroups since they can displace unevenly [#26888] */ + if ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) { + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + } + else if (do_shell) { + unsigned int i; + /* flip vertex normals for copied verts */ + mv = mvert + numVerts; + for (i = 0; i < numVerts; i++, mv++) { + negate_v3_short(mv->no); + } + } + + if (smd->flag & MOD_SOLIDIFY_RIM) { + unsigned int i; + + /* bugger, need to re-calculate the normals for the new edge faces. + * This could be done in many ways, but probably the quickest way + * is to calculate the average normals for side faces only. + * Then blend them with the normals of the edge verts. + * + * at the moment its easiest to allocate an entire array for every vertex, + * even though we only need edge verts - campbell + */ #define SOLIDIFY_SIDE_NORMALS #ifdef SOLIDIFY_SIDE_NORMALS - /* Note that, due to the code setting cd_dirty_vert a few lines above, - * do_side_normals is always false. - Sybren */ - const bool do_side_normals = !(result->runtime.cd_dirty_vert & CD_MASK_NORMAL); - /* annoying to allocate these since we only need the edge verts, */ - float (*edge_vert_nos)[3] = do_side_normals ? MEM_calloc_arrayN(numVerts, 3 * sizeof(float), __func__) : NULL; - float nor[3]; + /* Note that, due to the code setting cd_dirty_vert a few lines above, + * do_side_normals is always false. - Sybren */ + const bool do_side_normals = !(result->runtime.cd_dirty_vert & CD_MASK_NORMAL); + /* annoying to allocate these since we only need the edge verts, */ + float(*edge_vert_nos)[3] = do_side_normals ? + MEM_calloc_arrayN(numVerts, 3 * sizeof(float), __func__) : + NULL; + float nor[3]; #endif - const unsigned char crease_rim = smd->crease_rim * 255.0f; - const unsigned char crease_outer = smd->crease_outer * 255.0f; - const unsigned char crease_inner = smd->crease_inner * 255.0f; - - int *origindex_edge; - int *orig_ed; - unsigned int j; - - if (crease_rim || crease_outer || crease_inner) { - result->cd_flag |= ME_CDFLAG_EDGE_CREASE; - } - - /* add faces & edges */ - origindex_edge = CustomData_get_layer(&result->edata, CD_ORIGINDEX); - orig_ed = (origindex_edge) ? &origindex_edge[(numEdges * stride) + newEdges] : NULL; - ed = &medge[(numEdges * stride) + newEdges]; /* start after copied edges */ - for (i = 0; i < rimVerts; i++, ed++) { - ed->v1 = new_vert_arr[i]; - ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts; - ed->flag |= ME_EDGEDRAW | ME_EDGERENDER; - - if (orig_ed) { - *orig_ed = ORIGINDEX_NONE; - orig_ed++; - } - - if (crease_rim) { - ed->crease = crease_rim; - } - } - - /* faces */ - mp = mpoly + (numPolys * stride); - ml = mloop + (numLoops * stride); - j = 0; - for (i = 0; i < newPolys; i++, mp++) { - unsigned int eidx = new_edge_arr[i]; - unsigned int pidx = edge_users[eidx]; - int k1, k2; - bool flip; - - if (pidx >= numPolys) { - pidx -= numPolys; - flip = true; - } - else { - flip = false; - } - - ed = medge + eidx; - - /* copy most of the face settings */ - CustomData_copy_data(&mesh->pdata, &result->pdata, (int)pidx, (int)((numPolys * stride) + i), 1); - mp->loopstart = (int)(j + (numLoops * stride)); - mp->flag = mpoly[pidx].flag; - - /* notice we use 'mp->totloop' which is later overwritten, - * we could lookup the original face but there's no point since this is a copy - * and will have the same value, just take care when changing order of assignment */ - k1 = mpoly[pidx].loopstart + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop); /* prev loop */ - k2 = mpoly[pidx].loopstart + (edge_order[eidx]); - - mp->totloop = 4; - - CustomData_copy_data(&mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 0), 1); - CustomData_copy_data(&mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 1), 1); - CustomData_copy_data(&mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 2), 1); - CustomData_copy_data(&mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 3), 1); - - if (flip == false) { - ml[j].v = ed->v1; - ml[j++].e = eidx; - - ml[j].v = ed->v2; - ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges; - - ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts; - ml[j++].e = (do_shell ? eidx : i) + numEdges; - - ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts; - ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges; - } - else { - ml[j].v = ed->v2; - ml[j++].e = eidx; - - ml[j].v = ed->v1; - ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges; - - ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts; - ml[j++].e = (do_shell ? eidx : i) + numEdges; - - ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts; - ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges; - } - - if (origindex_edge) { - origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE; - origindex_edge[ml[j - 1].e] = ORIGINDEX_NONE; - } - - /* use the next material index if option enabled */ - if (mat_ofs_rim) { - mp->mat_nr += mat_ofs_rim; - CLAMP(mp->mat_nr, 0, mat_nr_max); - } - if (crease_outer) { - /* crease += crease_outer; without wrapping */ - char *cr = &(ed->crease); - int tcr = *cr + crease_outer; - *cr = tcr > 255 ? 255 : tcr; - } - - if (crease_inner) { - /* crease += crease_inner; without wrapping */ - char *cr = &(medge[numEdges + (do_shell ? eidx : i)].crease); - int tcr = *cr + crease_inner; - *cr = tcr > 255 ? 255 : tcr; - } + const unsigned char crease_rim = smd->crease_rim * 255.0f; + const unsigned char crease_outer = smd->crease_outer * 255.0f; + const unsigned char crease_inner = smd->crease_inner * 255.0f; + + int *origindex_edge; + int *orig_ed; + unsigned int j; + + if (crease_rim || crease_outer || crease_inner) { + result->cd_flag |= ME_CDFLAG_EDGE_CREASE; + } + + /* add faces & edges */ + origindex_edge = CustomData_get_layer(&result->edata, CD_ORIGINDEX); + orig_ed = (origindex_edge) ? &origindex_edge[(numEdges * stride) + newEdges] : NULL; + ed = &medge[(numEdges * stride) + newEdges]; /* start after copied edges */ + for (i = 0; i < rimVerts; i++, ed++) { + ed->v1 = new_vert_arr[i]; + ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts; + ed->flag |= ME_EDGEDRAW | ME_EDGERENDER; + + if (orig_ed) { + *orig_ed = ORIGINDEX_NONE; + orig_ed++; + } + + if (crease_rim) { + ed->crease = crease_rim; + } + } + + /* faces */ + mp = mpoly + (numPolys * stride); + ml = mloop + (numLoops * stride); + j = 0; + for (i = 0; i < newPolys; i++, mp++) { + unsigned int eidx = new_edge_arr[i]; + unsigned int pidx = edge_users[eidx]; + int k1, k2; + bool flip; + + if (pidx >= numPolys) { + pidx -= numPolys; + flip = true; + } + else { + flip = false; + } + + ed = medge + eidx; + + /* copy most of the face settings */ + CustomData_copy_data( + &mesh->pdata, &result->pdata, (int)pidx, (int)((numPolys * stride) + i), 1); + mp->loopstart = (int)(j + (numLoops * stride)); + mp->flag = mpoly[pidx].flag; + + /* notice we use 'mp->totloop' which is later overwritten, + * we could lookup the original face but there's no point since this is a copy + * and will have the same value, just take care when changing order of assignment */ + k1 = mpoly[pidx].loopstart + + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop); /* prev loop */ + k2 = mpoly[pidx].loopstart + (edge_order[eidx]); + + mp->totloop = 4; + + CustomData_copy_data( + &mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 0), 1); + CustomData_copy_data( + &mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 1), 1); + CustomData_copy_data( + &mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 2), 1); + CustomData_copy_data( + &mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 3), 1); + + if (flip == false) { + ml[j].v = ed->v1; + ml[j++].e = eidx; + + ml[j].v = ed->v2; + ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges; + + ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts; + ml[j++].e = (do_shell ? eidx : i) + numEdges; + + ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts; + ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges; + } + else { + ml[j].v = ed->v2; + ml[j++].e = eidx; + + ml[j].v = ed->v1; + ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges; + + ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts; + ml[j++].e = (do_shell ? eidx : i) + numEdges; + + ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts; + ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges; + } + + if (origindex_edge) { + origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE; + origindex_edge[ml[j - 1].e] = ORIGINDEX_NONE; + } + + /* use the next material index if option enabled */ + if (mat_ofs_rim) { + mp->mat_nr += mat_ofs_rim; + CLAMP(mp->mat_nr, 0, mat_nr_max); + } + if (crease_outer) { + /* crease += crease_outer; without wrapping */ + char *cr = &(ed->crease); + int tcr = *cr + crease_outer; + *cr = tcr > 255 ? 255 : tcr; + } + + if (crease_inner) { + /* crease += crease_inner; without wrapping */ + char *cr = &(medge[numEdges + (do_shell ? eidx : i)].crease); + int tcr = *cr + crease_inner; + *cr = tcr > 255 ? 255 : tcr; + } #ifdef SOLIDIFY_SIDE_NORMALS - if (do_side_normals) { - normal_quad_v3(nor, - mvert[ml[j - 4].v].co, - mvert[ml[j - 3].v].co, - mvert[ml[j - 2].v].co, - mvert[ml[j - 1].v].co); - - add_v3_v3(edge_vert_nos[ed->v1], nor); - add_v3_v3(edge_vert_nos[ed->v2], nor); - } + if (do_side_normals) { + normal_quad_v3(nor, + mvert[ml[j - 4].v].co, + mvert[ml[j - 3].v].co, + mvert[ml[j - 2].v].co, + mvert[ml[j - 1].v].co); + + add_v3_v3(edge_vert_nos[ed->v1], nor); + add_v3_v3(edge_vert_nos[ed->v2], nor); + } #endif - } + } #ifdef SOLIDIFY_SIDE_NORMALS - if (do_side_normals) { - const MEdge *ed_orig = medge; - ed = medge + (numEdges * stride); - for (i = 0; i < rimVerts; i++, ed++, ed_orig++) { - float nor_cpy[3]; - short *nor_short; - int k; - - /* note, only the first vertex (lower half of the index) is calculated */ - BLI_assert(ed->v1 < numVerts); - normalize_v3_v3(nor_cpy, edge_vert_nos[ed_orig->v1]); - - for (k = 0; k < 2; k++) { /* loop over both verts of the edge */ - nor_short = mvert[*(&ed->v1 + k)].no; - normal_short_to_float_v3(nor, nor_short); - add_v3_v3(nor, nor_cpy); - normalize_v3(nor); - normal_float_to_short_v3(nor_short, nor); - } - } - - MEM_freeN(edge_vert_nos); - } + if (do_side_normals) { + const MEdge *ed_orig = medge; + ed = medge + (numEdges * stride); + for (i = 0; i < rimVerts; i++, ed++, ed_orig++) { + float nor_cpy[3]; + short *nor_short; + int k; + + /* note, only the first vertex (lower half of the index) is calculated */ + BLI_assert(ed->v1 < numVerts); + normalize_v3_v3(nor_cpy, edge_vert_nos[ed_orig->v1]); + + for (k = 0; k < 2; k++) { /* loop over both verts of the edge */ + nor_short = mvert[*(&ed->v1 + k)].no; + normal_short_to_float_v3(nor, nor_short); + add_v3_v3(nor, nor_cpy); + normalize_v3(nor); + normal_float_to_short_v3(nor_short, nor); + } + } + + MEM_freeN(edge_vert_nos); + } #endif - MEM_freeN(new_vert_arr); - MEM_freeN(new_edge_arr); + MEM_freeN(new_vert_arr); + MEM_freeN(new_edge_arr); - MEM_freeN(edge_users); - MEM_freeN(edge_order); - } + MEM_freeN(edge_users); + MEM_freeN(edge_order); + } - if (old_vert_arr) - MEM_freeN(old_vert_arr); + if (old_vert_arr) + MEM_freeN(old_vert_arr); - if (poly_nors) - MEM_freeN(poly_nors); + if (poly_nors) + MEM_freeN(poly_nors); - if (numPolys == 0 && numEdges != 0) { - modifier_setError(md, "Faces needed for useful output"); - } + if (numPolys == 0 && numEdges != 0) { + modifier_setError(md, "Faces needed for useful output"); + } - return result; + return result; } #undef SOLIDIFY_SIDE_NORMALS static bool dependsOnNormals(ModifierData *UNUSED(md)) { - /* even when we calculate our own normals, - * the vertex normals are used as a fallback */ - return true; + /* even when we calculate our own normals, + * the vertex normals are used as a fallback */ + return true; } ModifierTypeInfo modifierType_Solidify = { - /* name */ "Solidify", - /* structName */ "SolidifyModifierData", - /* structSize */ sizeof(SolidifyModifierData), - /* type */ eModifierTypeType_Constructive, - - /* flags */ eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_AcceptsCVs | - eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode, - - /* copyData */ modifier_copyData_generic, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ dependsOnNormals, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* name */ "Solidify", + /* structName */ "SolidifyModifierData", + /* structSize */ sizeof(SolidifyModifierData), + /* type */ eModifierTypeType_Constructive, + + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs | + eModifierTypeFlag_SupportsMapping | eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ requiredDataMask, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ dependsOnNormals, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, }; |