Changeset View
Changeset View
Standalone View
Standalone View
source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
| Context not available. | |||||
| * \{ */ | * \{ */ | ||||
| /** | /** | ||||
| * Similar to #project_v3_v3v3_normalized that returns the dot-product. | * Similar to #project_v3_v3v3_normalized but returns the dot-product. | ||||
| */ | */ | ||||
| static float project_v3_v3(float r[3], const float a[3]) | static float project_v3_v3(float r[3], const float a[3]) | ||||
| { | { | ||||
| Context not available. | |||||
| return d; | return d; | ||||
| } | } | ||||
| /** | |||||
| * Similar to #angle_signed_on_axis_v3v3_v3 | |||||
| */ | |||||
| static float angle_signed_on_axis_normalized_v3v3_v3(const float n[3], | static float angle_signed_on_axis_normalized_v3v3_v3(const float n[3], | ||||
| const float ref_n[3], | const float ref_n[3], | ||||
| const float axis[3]) | const float axis[3]) | ||||
| { | { | ||||
| float d = dot_v3v3(n, ref_n); | float angle = angle_normalized_v3v3(n, ref_n); | ||||
| CLAMP(d, -1, 1); | |||||
| float angle = acosf(d); | |||||
| float cross[3]; | float cross[3]; | ||||
| cross_v3_v3v3(cross, n, ref_n); | cross_v3_v3v3(cross, n, ref_n); | ||||
| if (dot_v3v3(cross, axis) >= 0) { | if (dot_v3v3(cross, axis) >= 0) { | ||||
| Context not available. | |||||
| return angle; | return angle; | ||||
| } | } | ||||
| typedef struct PolyKeyPair { | |||||
| float angle; | |||||
| struct SolidifyPoly *poly; | |||||
| } PolyKeyPair; | |||||
| static int comp_float_int_pair(const void *a, const void *b) | |||||
| { | |||||
| PolyKeyPair *x = (PolyKeyPair *)a; | |||||
| PolyKeyPair *y = (PolyKeyPair *)b; | |||||
| return (int)(x->angle > y->angle) - (int)(x->angle < y->angle); | |||||
| } | |||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | #define MOD_SOLIDIFY_EMPTY_TAG ((uint)-1) | ||||
| /** \name Main Solidify Function | |||||
| * \{ */ | |||||
| /* Data structures for manifold solidify. */ | /* Data structures for manifold solidify. */ | ||||
| typedef struct NewFaceRef { | /* Data structures for temporal storage while reading the mesh. */ | ||||
| MPoly *face; | |||||
| uint index; | |||||
| bool reversed; | |||||
| struct NewEdgeRef **link_edges; | |||||
| } NewFaceRef; | |||||
| typedef struct OldEdgeFaceRef { | typedef struct EdgePolyLink { | ||||
| uint *faces; | uint *polys; | ||||
| uint faces_len; | uint polys_len; | ||||
| bool *faces_reversed; | bool *polys_reversed; | ||||
| uint used; | uint used; | ||||
| } OldEdgeFaceRef; | } EdgePolyLink; | ||||
| typedef struct OldVertEdgeRef { | typedef struct VertEdgeLink { | ||||
| uint *edges; | uint *edges; | ||||
| uint edges_len; | uint edges_len; | ||||
| } OldVertEdgeRef; | } VertEdgeLink; | ||||
| typedef struct NewEdgeRef { | /* Data structures for internal mesh format. */ | ||||
| uint old_edge; | |||||
| NewFaceRef *faces[2]; | typedef struct SolidifyPoly { | ||||
| struct EdgeGroup *link_edge_groups[2]; | MPoly *poly; | ||||
| uint orig_poly_index; | |||||
| bool reversed; | |||||
| struct SolidifyEdge **link_edges; | |||||
| } SolidifyPoly; | |||||
| typedef struct SolidifyEdge { | |||||
| uint orig_edge; | |||||
| SolidifyPoly *polys[2]; | |||||
| struct SolidifyCorner *link_corners[2]; | |||||
| float angle; | float angle; | ||||
| uint new_edge; | uint new_edge; | ||||
| } NewEdgeRef; | } SolidifyEdge; | ||||
| typedef struct EdgeGroup { | /* Defines a vertex in the new mesh. Because it contains also information about near geometry it is | ||||
| * called a corner to to distinguish it from the actual vertices. */ | |||||
| typedef struct SolidifyCorner { | |||||
| bool valid; | bool valid; | ||||
| NewEdgeRef **edges; | SolidifyEdge **edges; | ||||
| uint edges_len; | uint edges_len; | ||||
| uint open_face_edge; | uint open_poly_edge; | ||||
| bool is_orig_closed; | bool is_orig_closed; | ||||
| bool is_even_split; | bool is_even_split; | ||||
| uint split; | uint split; | ||||
| Context not available. | |||||
| float co[3]; | float co[3]; | ||||
| float no[3]; | float no[3]; | ||||
| uint new_vert; | uint new_vert; | ||||
| } EdgeGroup; | } SolidifyCorner; | ||||
| /* Context structure for the mesh building process. | |||||
| * Contains only data about the newly created mesh. */ | |||||
| typedef struct SolidifyMesh { | |||||
| uint numVerts; | |||||
| uint numEdges; | |||||
| uint numLoops; | |||||
| uint numPolys; | |||||
| bool has_singularities; | |||||
| /* Contains an array of new polys for every poly in the original mesh. | |||||
| * The index in this array is [(i * 2) + r] where i is the index in the | |||||
| * original mesh and r specifies the orientation (0 = same as original, 1 = opposite) */ | |||||
| SolidifyPoly *polys; | |||||
| /* Contains an array of new edges (as pointers) for every edge in the original mesh. */ | |||||
| SolidifyEdge ***edges; | |||||
| /* Contains an array of new corners for every vert in the original mesh. */ | |||||
| SolidifyCorner **corners_from_vert; | |||||
| /* Initialized once the element counting is finished. */ | |||||
| Mesh *mesh; | |||||
| } SolidifyMesh; | |||||
| typedef struct SolidifyContext { | |||||
| SolidifyMesh *result; | |||||
| SolidifyModifierData *smd; | |||||
| Mesh *mesh; | |||||
| /* Execution constants. */ | |||||
| short mat_nrs; | |||||
| short mat_nr_max; | |||||
| short mat_ofs; | |||||
| short mat_ofs_rim; | |||||
| float ofs_front; | |||||
| float ofs_back; | |||||
| float ofs_front_clamped; | |||||
| float ofs_back_clamped; | |||||
| float offset_fac_vg; | |||||
| float offset_fac_vg_inv; | |||||
| float offset; | |||||
| bool do_angle_clamp; | |||||
| bool do_flip; | |||||
| bool do_rim; | |||||
| bool do_shell; | |||||
| bool do_clamp; | |||||
| float bevel_convex; | |||||
| bool do_flat_faces; | |||||
| typedef struct FaceKeyPair { | MDeformVert *dvert; | ||||
| float angle; | bool defgrp_invert; | ||||
| NewFaceRef *face; | int defgrp_index; | ||||
| } FaceKeyPair; | int shell_defgrp_index; | ||||
| int rim_defgrp_index; | |||||
| /* Runtime variables. */ | |||||
| float(*poly_nors)[3]; | |||||
| bool *null_polys; | |||||
| uint *vm; | |||||
| float(*orig_mvert_co)[3]; | |||||
| uint *edge_adj_polys_len; | |||||
| float *orig_edge_lengths; | |||||
| uint largest_ngon; | |||||
| uint(*singularity_edges)[2]; | |||||
| uint totsingularity; | |||||
| } SolidifyContext; | |||||
| static int comp_float_int_pair(const void *a, const void *b) | /** \} */ | ||||
| { | |||||
| FaceKeyPair *x = (FaceKeyPair *)a; | |||||
| FaceKeyPair *y = (FaceKeyPair *)b; | |||||
| return (int)(x->angle > y->angle) - (int)(x->angle < y->angle); | |||||
| } | |||||
| Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, | /* -------------------------------------------------------------------- */ | ||||
| const ModifierEvalContext *ctx, | /** \name Solidify Steps split up in multiple Functions | ||||
| Mesh *mesh) | * \{ */ | ||||
| { | |||||
| Mesh *result; | |||||
| const SolidifyModifierData *smd = (SolidifyModifierData *)md; | |||||
| MVert *mv, *mvert, *orig_mvert; | static void solidify_prepare_mesh_structure(SolidifyContext *sctx) { | ||||
| MEdge *ed, *medge, *orig_medge; | SolidifyMesh *result = sctx->result; | ||||
| MLoop *ml, *mloop, *orig_mloop; | const SolidifyModifierData *smd = sctx->smd; | ||||
| MPoly *mp, *mpoly, *orig_mpoly; | const Mesh *mesh = sctx->mesh; | ||||
| float(*poly_nors)[3] = sctx->poly_nors; | |||||
| MVert *orig_mvert; | |||||
| MEdge *ed, *orig_medge; | |||||
| MLoop *ml, *orig_mloop; | |||||
| MPoly *mp, *orig_mpoly; | |||||
| const uint numVerts = (uint)mesh->totvert; | const uint numVerts = (uint)mesh->totvert; | ||||
| const uint numEdges = (uint)mesh->totedge; | const uint numEdges = (uint)mesh->totedge; | ||||
| const uint numPolys = (uint)mesh->totpoly; | const uint numPolys = (uint)mesh->totpoly; | ||||
| const uint numLoops = (uint)mesh->totloop; | |||||
| if (numPolys == 0 && numVerts != 0) { | |||||
| return mesh; | |||||
| } | |||||
| /* Only use material offsets if we have 2 or more materials. */ | |||||
| const short mat_nrs = ctx->object->totcol > 1 ? ctx->object->totcol : 1; | |||||
| const short mat_nr_max = mat_nrs - 1; | |||||
| const short mat_ofs = mat_nrs > 1 ? smd->mat_ofs : 0; | |||||
| const short mat_ofs_rim = mat_nrs > 1 ? smd->mat_ofs_rim : 0; | |||||
| float(*poly_nors)[3] = NULL; | |||||
| const float ofs_front = (smd->offset_fac + 1.0f) * 0.5f * smd->offset; | |||||
| const float ofs_back = ofs_front - smd->offset * smd->offset_fac; | |||||
| const float ofs_front_clamped = max_ff(1e-5f, fabsf(smd->offset > 0 ? ofs_front : ofs_back)); | |||||
| const float ofs_back_clamped = max_ff(1e-5f, fabsf(smd->offset > 0 ? ofs_back : ofs_front)); | |||||
| const float offset_fac_vg = smd->offset_fac_vg; | |||||
| const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg; | |||||
| const float offset = fabsf(smd->offset) * smd->offset_clamp; | |||||
| const bool do_angle_clamp = smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP; | |||||
| const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0; | |||||
| const bool do_rim = smd->flag & MOD_SOLIDIFY_RIM; | |||||
| const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == | |||||
| 0; | |||||
| const bool do_clamp = (smd->offset_clamp != 0.0f); | |||||
| const float bevel_convex = smd->bevel_convex; | |||||
| MDeformVert *dvert; | |||||
| const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0; | |||||
| int defgrp_index; | |||||
| const int shell_defgrp_index = BKE_object_defgroup_name_index(ctx->object, | |||||
| smd->shell_defgrp_name); | |||||
| const int rim_defgrp_index = BKE_object_defgroup_name_index(ctx->object, smd->rim_defgrp_name); | |||||
| MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index); | |||||
| const bool do_flat_faces = dvert && (smd->flag & MOD_SOLIDIFY_NONMANIFOLD_FLAT_FACES); | |||||
| orig_mvert = mesh->mvert; | orig_mvert = mesh->mvert; | ||||
| orig_medge = mesh->medge; | orig_medge = mesh->medge; | ||||
| orig_mloop = mesh->mloop; | orig_mloop = mesh->mloop; | ||||
| orig_mpoly = mesh->mpoly; | orig_mpoly = mesh->mpoly; | ||||
| uint numNewVerts = 0; | result->polys = MEM_malloc_arrayN( | ||||
| uint numNewEdges = 0; | numPolys * 2, sizeof(*result->polys), "SolidifyMesh::polys in solidify"); | ||||
| uint numNewLoops = 0; | sctx->largest_ngon = 3; | ||||
| uint numNewPolys = 0; | /* Calculate poly to #SolidifyPoly map. */ | ||||
| #define MOD_SOLIDIFY_EMPTY_TAG ((uint)-1) | |||||
| /* 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); | |||||
| NewFaceRef *face_sides_arr = MEM_malloc_arrayN( | |||||
| numPolys * 2, sizeof(*face_sides_arr), "face_sides_arr in solidify"); | |||||
| bool *null_faces = | |||||
| (smd->nonmanifold_offset_mode == MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS) ? | |||||
| MEM_calloc_arrayN(numPolys, sizeof(*null_faces), "null_faces in solidify") : | |||||
| NULL; | |||||
| uint largest_ngon = 3; | |||||
| /* Calculate face to #NewFaceRef map. */ | |||||
| { | { | ||||
| mp = orig_mpoly; | mp = orig_mpoly; | ||||
| for (uint i = 0; i < numPolys; i++, mp++) { | for (uint i = 0; i < numPolys; i++, mp++) { | ||||
| /* Make normals for faces without area (should really be avoided though). */ | /* Make normals for polys without area (should really be avoided though). */ | ||||
| if (len_squared_v3(poly_nors[i]) < 0.5f) { | if (len_squared_v3(poly_nors[i]) < 0.5f) { | ||||
| MEdge *e = orig_medge + orig_mloop[mp->loopstart].e; | MEdge *e = orig_medge + orig_mloop[mp->loopstart].e; | ||||
| float edgedir[3]; | float edgedir[3]; | ||||
| Context not available. | |||||
| else { | else { | ||||
| poly_nors[i][1] = 1.0f; | poly_nors[i][1] = 1.0f; | ||||
| } | } | ||||
| if (null_faces) { | if (sctx->null_polys) { | ||||
| null_faces[i] = true; | sctx->null_polys[i] = true; | ||||
| } | } | ||||
| } | } | ||||
| NewEdgeRef **link_edges = MEM_calloc_arrayN( | SolidifyEdge **link_edges = MEM_calloc_arrayN( | ||||
| (uint)mp->totloop, sizeof(*link_edges), "NewFaceRef::link_edges in solidify"); | (uint)mp->totloop, sizeof(*link_edges), "SolidifyPoly::link_edges in solidify"); | ||||
| face_sides_arr[i * 2] = (NewFaceRef){ | result->polys[i * 2] = (SolidifyPoly){ | ||||
| .face = mp, .index = i, .reversed = false, .link_edges = link_edges}; | .poly = mp, .orig_poly_index = i, .reversed = false, .link_edges = link_edges}; | ||||
| link_edges = MEM_calloc_arrayN( | link_edges = MEM_calloc_arrayN( | ||||
| (uint)mp->totloop, sizeof(*link_edges), "NewFaceRef::link_edges in solidify"); | (uint)mp->totloop, sizeof(*link_edges), "SolidifyPoly::link_edges in solidify"); | ||||
| face_sides_arr[i * 2 + 1] = (NewFaceRef){ | result->polys[i * 2 + 1] = (SolidifyPoly){ | ||||
| .face = mp, .index = i, .reversed = true, .link_edges = link_edges}; | .poly = mp, .orig_poly_index = i, .reversed = true, .link_edges = link_edges}; | ||||
| if (mp->totloop > largest_ngon) { | if (mp->totloop > sctx->largest_ngon) { | ||||
| largest_ngon = (uint)mp->totloop; | sctx->largest_ngon = (uint)mp->totloop; | ||||
| } | } | ||||
| /* add to final mesh face count */ | /* add to final mesh poly count */ | ||||
| if (do_shell) { | if (sctx->do_shell) { | ||||
| numNewPolys += 2; | result->numPolys += 2; | ||||
| numNewLoops += (uint)mp->totloop * 2; | result->numLoops += (uint)mp->totloop * 2; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| uint *edge_adj_faces_len = MEM_calloc_arrayN( | uint *edge_adj_polys_len = MEM_calloc_arrayN( | ||||
| numEdges, sizeof(*edge_adj_faces_len), "edge_adj_faces_len in solidify"); | numEdges, sizeof(*edge_adj_polys_len), "edge_adj_polys_len in solidify"); | ||||
| /* Count for each edge how many faces it has adjacent. */ | sctx->edge_adj_polys_len = edge_adj_polys_len; | ||||
| /* Count for each edge how many polys it has adjacent. */ | |||||
| { | { | ||||
| mp = orig_mpoly; | mp = orig_mpoly; | ||||
| for (uint i = 0; i < numPolys; i++, mp++) { | for (uint i = 0; i < numPolys; i++, mp++) { | ||||
| ml = orig_mloop + mp->loopstart; | ml = orig_mloop + mp->loopstart; | ||||
| for (uint j = 0; j < mp->totloop; j++, ml++) { | for (uint j = 0; j < mp->totloop; j++, ml++) { | ||||
| edge_adj_faces_len[ml->e]++; | edge_adj_polys_len[ml->e]++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Original edge to #NewEdgeRef map. */ | /* Original edge to #SolidifyEdge map. */ | ||||
| NewEdgeRef ***orig_edge_data_arr = MEM_calloc_arrayN( | result->edges = MEM_calloc_arrayN(numEdges, sizeof(*result->edges), "SolidifyMesh::edges in solidify"); | ||||
| numEdges, sizeof(*orig_edge_data_arr), "orig_edge_data_arr in solidify"); | |||||
| /* Original edge length cache. */ | /* Original edge length cache. */ | ||||
| float *orig_edge_lengths = MEM_calloc_arrayN( | float *orig_edge_lengths = MEM_calloc_arrayN( | ||||
| numEdges, sizeof(*orig_edge_lengths), "orig_edge_lengths in solidify"); | numEdges, sizeof(*orig_edge_lengths), "orig_edge_lengths in solidify"); | ||||
| /* Edge groups for every original vert. */ | sctx->orig_edge_lengths = orig_edge_lengths; | ||||
| EdgeGroup **orig_vert_groups_arr = MEM_calloc_arrayN( | /* Corner arrays for every original vert. */ | ||||
| numVerts, sizeof(*orig_vert_groups_arr), "orig_vert_groups_arr in solidify"); | result->corners_from_vert = MEM_calloc_arrayN( | ||||
| numVerts, sizeof(*result->corners_from_vert), "SolidifyMesh::corners_from_vert in solidify"); | |||||
| /* vertex map used to map duplicates. */ | /* vertex map used to map duplicates. */ | ||||
| uint *vm = MEM_malloc_arrayN(numVerts, sizeof(*vm), "orig_vert_map in solidify"); | uint *vm = MEM_malloc_arrayN(numVerts, sizeof(*vm), "orig_vert_map in solidify"); | ||||
| for (uint i = 0; i < numVerts; i++) { | for (uint i = 0; i < numVerts; i++) { | ||||
| vm[i] = i; | vm[i] = i; | ||||
| } | } | ||||
| sctx->vm = vm; | |||||
| uint edge_index = 0; | |||||
| uint loop_index = 0; | |||||
| uint poly_index = 0; | |||||
| bool has_singularities = false; | |||||
| /* Vert edge adjacent map. */ | /* Vert edge adjacent map. */ | ||||
| OldVertEdgeRef **vert_adj_edges = MEM_calloc_arrayN( | VertEdgeLink **vert_adj_edges = MEM_calloc_arrayN( | ||||
| numVerts, sizeof(*vert_adj_edges), "vert_adj_edges in solidify"); | numVerts, sizeof(*vert_adj_edges), "vert_adj_edges in solidify"); | ||||
| /* Original vertex positions (changed for degenerated geometry). */ | /* Original vertex positions (changed for degenerated geometry). */ | ||||
| float(*orig_mvert_co)[3] = MEM_malloc_arrayN( | float(*orig_mvert_co)[3] = MEM_malloc_arrayN( | ||||
| numVerts, sizeof(*orig_mvert_co), "orig_mvert_co in solidify"); | numVerts, sizeof(*orig_mvert_co), "orig_mvert_co in solidify"); | ||||
| /* Fill in the original vertex positions. */ | /* Fill in the original vertex positions. */ | ||||
| for (uint i = 0; i < numVerts; i++) { | for (uint i = 0; i < numVerts; i++) { | ||||
| orig_mvert_co[i][0] = orig_mvert[i].co[0]; | copy_v3_v3(orig_mvert_co[i], orig_mvert[i].co); | ||||
| orig_mvert_co[i][1] = orig_mvert[i].co[1]; | |||||
| orig_mvert_co[i][2] = orig_mvert[i].co[2]; | |||||
| } | } | ||||
| sctx->orig_mvert_co = orig_mvert_co; | |||||
| /* Create edge to #NewEdgeRef map. */ | /* Create edge to #SolidifyEdge map. */ | ||||
| { | { | ||||
| OldEdgeFaceRef **edge_adj_faces = MEM_calloc_arrayN( | EdgePolyLink **edge_adj_polys = MEM_calloc_arrayN( | ||||
| numEdges, sizeof(*edge_adj_faces), "edge_adj_faces in solidify"); | numEdges, sizeof(*edge_adj_polys), "edge_adj_polys in solidify"); | ||||
| /* Create link_faces for edges. */ | /* Create link_polys for edges. */ | ||||
| { | { | ||||
| mp = orig_mpoly; | mp = orig_mpoly; | ||||
| for (uint i = 0; i < numPolys; i++, mp++) { | for (uint i = 0; i < numPolys; i++, mp++) { | ||||
| Context not available. | |||||
| for (uint j = 0; j < mp->totloop; j++, ml++) { | for (uint j = 0; j < mp->totloop; j++, ml++) { | ||||
| const uint edge = ml->e; | const uint edge = ml->e; | ||||
| const bool reversed = orig_medge[edge].v2 != ml->v; | const bool reversed = orig_medge[edge].v2 != ml->v; | ||||
| OldEdgeFaceRef *old_face_edge_ref = edge_adj_faces[edge]; | EdgePolyLink *orig_poly_edge = edge_adj_polys[edge]; | ||||
| if (old_face_edge_ref == NULL) { | if (orig_poly_edge == NULL) { | ||||
| const uint len = edge_adj_faces_len[edge]; | const uint len = edge_adj_polys_len[edge]; | ||||
| BLI_assert(len > 0); | BLI_assert(len > 0); | ||||
| uint *adj_faces = MEM_malloc_arrayN( | uint *adj_polys = MEM_malloc_arrayN( | ||||
| len, sizeof(*adj_faces), "OldEdgeFaceRef::faces in solidify"); | len, sizeof(*adj_polys), "EdgePolyLink::polys in solidify"); | ||||
| bool *adj_faces_reversed = MEM_malloc_arrayN( | bool *adj_polys_reversed = MEM_malloc_arrayN( | ||||
| len, sizeof(*adj_faces_reversed), "OldEdgeFaceRef::reversed in solidify"); | len, sizeof(*adj_polys_reversed), "EdgePolyLink::reversed in solidify"); | ||||
| adj_faces[0] = i; | adj_polys[0] = i; | ||||
| for (uint k = 1; k < len; k++) { | for (uint k = 1; k < len; k++) { | ||||
| adj_faces[k] = MOD_SOLIDIFY_EMPTY_TAG; | adj_polys[k] = MOD_SOLIDIFY_EMPTY_TAG; | ||||
| } | } | ||||
| adj_faces_reversed[0] = reversed; | adj_polys_reversed[0] = reversed; | ||||
| OldEdgeFaceRef *ref = MEM_mallocN(sizeof(*ref), "OldEdgeFaceRef in solidify"); | EdgePolyLink *ref = MEM_mallocN(sizeof(*ref), "EdgePolyLink in solidify"); | ||||
| *ref = (OldEdgeFaceRef){adj_faces, len, adj_faces_reversed, 1}; | *ref = (EdgePolyLink){adj_polys, len, adj_polys_reversed, 1}; | ||||
| edge_adj_faces[edge] = ref; | edge_adj_polys[edge] = ref; | ||||
| } | } | ||||
| else { | else { | ||||
| for (uint k = 1; k < old_face_edge_ref->faces_len; k++) { | for (uint k = 1; k < orig_poly_edge->polys_len; k++) { | ||||
| if (old_face_edge_ref->faces[k] == MOD_SOLIDIFY_EMPTY_TAG) { | if (orig_poly_edge->polys[k] == MOD_SOLIDIFY_EMPTY_TAG) { | ||||
| old_face_edge_ref->faces[k] = i; | orig_poly_edge->polys[k] = i; | ||||
| old_face_edge_ref->faces_reversed[k] = reversed; | orig_poly_edge->polys_reversed[k] = reversed; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| /* Calculate edge lengths and len vert_adj edges. */ | /* Calculate edge lengths and len vert_adj edges. */ | ||||
| { | { | ||||
| bool *face_singularity = MEM_calloc_arrayN( | bool *poly_singularity = MEM_calloc_arrayN( | ||||
| numPolys, sizeof(*face_singularity), "face_sides_arr in solidify"); | numPolys, sizeof(*poly_singularity), "poly_singularity in solidify"); | ||||
| const float merge_tolerance_sqr = smd->merge_tolerance * smd->merge_tolerance; | const float merge_tolerance_sqr = square_f(smd->merge_tolerance); | ||||
| uint *combined_verts = MEM_calloc_arrayN( | uint *combined_verts = MEM_calloc_arrayN( | ||||
| numVerts, sizeof(*combined_verts), "combined_verts in solidify"); | numVerts, sizeof(*combined_verts), "combined_verts in solidify"); | ||||
| ed = orig_medge; | ed = orig_medge; | ||||
| for (uint i = 0; i < numEdges; i++, ed++) { | for (uint i = 0; i < numEdges; i++, ed++) { | ||||
| if (edge_adj_faces_len[i] > 0) { | if (edge_adj_polys_len[i] > 0) { | ||||
| uint v1 = vm[ed->v1]; | uint v1 = vm[ed->v1]; | ||||
| uint v2 = vm[ed->v2]; | uint v2 = vm[ed->v2]; | ||||
| if (v1 != v2) { | if (v1 != v2) { | ||||
| Context not available. | |||||
| vert_adj_edges_len[v2] = 0; | vert_adj_edges_len[v2] = 0; | ||||
| combined_verts[v1] += combined_verts[v2] + 1; | combined_verts[v1] += combined_verts[v2] + 1; | ||||
| if (do_shell) { | if (sctx->do_shell) { | ||||
| numNewLoops -= edge_adj_faces_len[i] * 2; | result->numLoops -= edge_adj_polys_len[i] * 2; | ||||
| } | } | ||||
| edge_adj_faces_len[i] = 0; | edge_adj_polys_len[i] = 0; | ||||
| MEM_freeN(edge_adj_faces[i]->faces); | MEM_freeN(edge_adj_polys[i]->polys); | ||||
| MEM_freeN(edge_adj_faces[i]->faces_reversed); | MEM_freeN(edge_adj_polys[i]->polys_reversed); | ||||
| MEM_freeN(edge_adj_faces[i]); | MEM_freeN(edge_adj_polys[i]); | ||||
| edge_adj_faces[i] = NULL; | edge_adj_polys[i] = NULL; | ||||
| } | } | ||||
| else { | else { | ||||
| orig_edge_lengths[i] = sqrtf(orig_edge_lengths[i]); | orig_edge_lengths[i] = sqrtf(orig_edge_lengths[i]); | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* remove zero faces in a second pass */ | /* remove zero polys in a second pass */ | ||||
| ed = orig_medge; | ed = orig_medge; | ||||
| for (uint i = 0; i < numEdges; i++, ed++) { | for (uint i = 0; i < numEdges; i++, ed++) { | ||||
| const uint v1 = vm[ed->v1]; | const uint v1 = vm[ed->v1]; | ||||
| const uint v2 = vm[ed->v2]; | const uint v2 = vm[ed->v2]; | ||||
| if (v1 == v2 && edge_adj_faces[i]) { | if (v1 == v2 && edge_adj_polys[i]) { | ||||
| /* Remove polys. */ | /* Remove polys. */ | ||||
| for (uint j = 0; j < edge_adj_faces[i]->faces_len; j++) { | for (uint j = 0; j < edge_adj_polys[i]->polys_len; j++) { | ||||
| const uint face = edge_adj_faces[i]->faces[j]; | const uint poly = edge_adj_polys[i]->polys[j]; | ||||
| if (!face_singularity[face]) { | if (!poly_singularity[poly]) { | ||||
| bool is_singularity = true; | bool is_singularity = true; | ||||
| for (uint k = 0; k < orig_mpoly[face].totloop; k++) { | for (uint k = 0; k < orig_mpoly[poly].totloop; k++) { | ||||
| if (vm[orig_mloop[((uint)orig_mpoly[face].loopstart) + k].v] != v1) { | if (vm[orig_mloop[((uint)orig_mpoly[poly].loopstart) + k].v] != v1) { | ||||
| is_singularity = false; | is_singularity = false; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (is_singularity) { | if (is_singularity) { | ||||
| face_singularity[face] = true; | poly_singularity[poly] = true; | ||||
| /* remove from final mesh poly count */ | /* remove from final mesh poly count */ | ||||
| if (do_shell) { | if (sctx->do_shell) { | ||||
| numNewPolys -= 2; | result->numPolys -= 2; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (do_shell) { | if (sctx->do_shell) { | ||||
| numNewLoops -= edge_adj_faces_len[i] * 2; | result->numLoops -= edge_adj_polys_len[i] * 2; | ||||
| } | } | ||||
| edge_adj_faces_len[i] = 0; | edge_adj_polys_len[i] = 0; | ||||
| MEM_freeN(edge_adj_faces[i]->faces); | MEM_freeN(edge_adj_polys[i]->polys); | ||||
| MEM_freeN(edge_adj_faces[i]->faces_reversed); | MEM_freeN(edge_adj_polys[i]->polys_reversed); | ||||
| MEM_freeN(edge_adj_faces[i]); | MEM_freeN(edge_adj_polys[i]); | ||||
| edge_adj_faces[i] = NULL; | edge_adj_polys[i] = NULL; | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(face_singularity); | MEM_freeN(poly_singularity); | ||||
| MEM_freeN(combined_verts); | MEM_freeN(combined_verts); | ||||
| } | } | ||||
| Context not available. | |||||
| { | { | ||||
| ed = orig_medge; | ed = orig_medge; | ||||
| for (uint i = 0; i < numEdges; i++, ed++) { | for (uint i = 0; i < numEdges; i++, ed++) { | ||||
| if (edge_adj_faces_len[i] > 0) { | if (edge_adj_polys_len[i] > 0) { | ||||
| const uint vs[2] = {vm[ed->v1], vm[ed->v2]}; | const uint vs[2] = {vm[ed->v1], vm[ed->v2]}; | ||||
| uint invalid_edge_index = 0; | uint invalid_edge_index = 0; | ||||
| bool invalid_edge_reversed = false; | bool invalid_edge_reversed = false; | ||||
| Context not available. | |||||
| const uint vert = vs[j]; | const uint vert = vs[j]; | ||||
| const uint len = vert_adj_edges_len[vert]; | const uint len = vert_adj_edges_len[vert]; | ||||
| if (len > 0) { | if (len > 0) { | ||||
| OldVertEdgeRef *old_edge_vert_ref = vert_adj_edges[vert]; | VertEdgeLink *orig_edge_vert = vert_adj_edges[vert]; | ||||
| if (old_edge_vert_ref == NULL) { | if (orig_edge_vert == NULL) { | ||||
| uint *adj_edges = MEM_calloc_arrayN( | uint *adj_edges = MEM_calloc_arrayN( | ||||
| len, sizeof(*adj_edges), "OldVertEdgeRef::edges in solidify"); | len, sizeof(*adj_edges), "VertEdgeLink::edges in solidify"); | ||||
| adj_edges[0] = i; | adj_edges[0] = i; | ||||
| for (uint k = 1; k < len; k++) { | for (uint k = 1; k < len; k++) { | ||||
| adj_edges[k] = MOD_SOLIDIFY_EMPTY_TAG; | adj_edges[k] = MOD_SOLIDIFY_EMPTY_TAG; | ||||
| } | } | ||||
| OldVertEdgeRef *ref = MEM_mallocN(sizeof(*ref), "OldVertEdgeRef in solidify"); | VertEdgeLink *ref = MEM_mallocN(sizeof(*ref), "VertEdgeLink in solidify"); | ||||
| *ref = (OldVertEdgeRef){adj_edges, 1}; | *ref = (VertEdgeLink){adj_edges, 1}; | ||||
| vert_adj_edges[vert] = ref; | vert_adj_edges[vert] = ref; | ||||
| } | } | ||||
| else { | else { | ||||
| const uint *f = old_edge_vert_ref->edges; | const uint *f = orig_edge_vert->edges; | ||||
| for (uint k = 0; k < len && k <= old_edge_vert_ref->edges_len; k++, f++) { | for (uint k = 0; k < len && k <= orig_edge_vert->edges_len; k++, f++) { | ||||
| const uint edge = old_edge_vert_ref->edges[k]; | const uint edge = orig_edge_vert->edges[k]; | ||||
| if (edge == MOD_SOLIDIFY_EMPTY_TAG || k == old_edge_vert_ref->edges_len) { | if (edge == MOD_SOLIDIFY_EMPTY_TAG || k == orig_edge_vert->edges_len) { | ||||
| old_edge_vert_ref->edges[k] = i; | orig_edge_vert->edges[k] = i; | ||||
| old_edge_vert_ref->edges_len++; | orig_edge_vert->edges_len++; | ||||
| break; | break; | ||||
| } | } | ||||
| else if (vm[orig_medge[edge].v1] == vs[1 - j]) { | else if (vm[orig_medge[edge].v1] == vs[1 - j]) { | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Remove zero faces that are in shape of an edge. */ | /* Remove zero polys that are in shape of an edge. */ | ||||
| if (invalid_edge_index) { | if (invalid_edge_index) { | ||||
| const uint tmp = invalid_edge_index - 1; | const uint tmp = invalid_edge_index - 1; | ||||
| invalid_edge_index = i; | invalid_edge_index = i; | ||||
| i = tmp; | i = tmp; | ||||
| OldEdgeFaceRef *i_adj_faces = edge_adj_faces[i]; | EdgePolyLink *i_adj_polys = edge_adj_polys[i]; | ||||
| OldEdgeFaceRef *invalid_adj_faces = edge_adj_faces[invalid_edge_index]; | EdgePolyLink *invalid_adj_polys = edge_adj_polys[invalid_edge_index]; | ||||
| uint j = 0; | uint j = 0; | ||||
| for (uint k = 0; k < i_adj_faces->faces_len; k++) { | for (uint k = 0; k < i_adj_polys->polys_len; k++) { | ||||
| for (uint l = 0; l < invalid_adj_faces->faces_len; l++) { | for (uint l = 0; l < invalid_adj_polys->polys_len; l++) { | ||||
| if (i_adj_faces->faces[k] == invalid_adj_faces->faces[l] && | if (i_adj_polys->polys[k] == invalid_adj_polys->polys[l] && | ||||
| i_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG) { | i_adj_polys->polys[k] != MOD_SOLIDIFY_EMPTY_TAG) { | ||||
| i_adj_faces->faces[k] = MOD_SOLIDIFY_EMPTY_TAG; | i_adj_polys->polys[k] = MOD_SOLIDIFY_EMPTY_TAG; | ||||
| invalid_adj_faces->faces[l] = MOD_SOLIDIFY_EMPTY_TAG; | invalid_adj_polys->polys[l] = MOD_SOLIDIFY_EMPTY_TAG; | ||||
| j++; | j++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* remove from final face count */ | /* remove from final poly count */ | ||||
| if (do_shell) { | if (sctx->do_shell) { | ||||
| numNewPolys -= 2 * j; | result->numPolys -= 2 * j; | ||||
| numNewLoops -= 4 * j; | result->numLoops -= 4 * j; | ||||
| } | } | ||||
| const uint len = i_adj_faces->faces_len + invalid_adj_faces->faces_len - 2 * j; | const uint len = i_adj_polys->polys_len + invalid_adj_polys->polys_len - 2 * j; | ||||
| uint *adj_faces = MEM_malloc_arrayN( | uint *adj_polys = MEM_malloc_arrayN( | ||||
| len, sizeof(*adj_faces), "OldEdgeFaceRef::faces in solidify"); | len, sizeof(*adj_polys), "EdgePolyLink::polys in solidify"); | ||||
| bool *adj_faces_loops_reversed = MEM_malloc_arrayN( | bool *adj_polys_loops_reversed = MEM_malloc_arrayN( | ||||
| len, sizeof(*adj_faces_loops_reversed), "OldEdgeFaceRef::reversed in solidify"); | len, sizeof(*adj_polys_loops_reversed), "EdgePolyLink::reversed in solidify"); | ||||
| /* Clean merge of adj_faces. */ | /* Clean merge of adj_polys. */ | ||||
| j = 0; | j = 0; | ||||
| for (uint k = 0; k < i_adj_faces->faces_len; k++) { | for (uint k = 0; k < i_adj_polys->polys_len; k++) { | ||||
| if (i_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG) { | if (i_adj_polys->polys[k] != MOD_SOLIDIFY_EMPTY_TAG) { | ||||
| adj_faces[j] = i_adj_faces->faces[k]; | adj_polys[j] = i_adj_polys->polys[k]; | ||||
| adj_faces_loops_reversed[j++] = i_adj_faces->faces_reversed[k]; | adj_polys_loops_reversed[j++] = i_adj_polys->polys_reversed[k]; | ||||
| } | } | ||||
| } | } | ||||
| for (uint k = 0; k < invalid_adj_faces->faces_len; k++) { | for (uint k = 0; k < invalid_adj_polys->polys_len; k++) { | ||||
| if (invalid_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG) { | if (invalid_adj_polys->polys[k] != MOD_SOLIDIFY_EMPTY_TAG) { | ||||
| adj_faces[j] = invalid_adj_faces->faces[k]; | adj_polys[j] = invalid_adj_polys->polys[k]; | ||||
| adj_faces_loops_reversed[j++] = (invalid_edge_reversed != | adj_polys_loops_reversed[j++] = (invalid_edge_reversed != | ||||
| invalid_adj_faces->faces_reversed[k]); | invalid_adj_polys->polys_reversed[k]); | ||||
| } | } | ||||
| } | } | ||||
| BLI_assert(j == len); | BLI_assert(j == len); | ||||
| edge_adj_faces_len[invalid_edge_index] = 0; | edge_adj_polys_len[invalid_edge_index] = 0; | ||||
| edge_adj_faces_len[i] = len; | edge_adj_polys_len[i] = len; | ||||
| MEM_freeN(i_adj_faces->faces); | MEM_freeN(i_adj_polys->polys); | ||||
| MEM_freeN(i_adj_faces->faces_reversed); | MEM_freeN(i_adj_polys->polys_reversed); | ||||
| i_adj_faces->faces_len = len; | i_adj_polys->polys_len = len; | ||||
| i_adj_faces->faces = adj_faces; | i_adj_polys->polys = adj_polys; | ||||
| i_adj_faces->faces_reversed = adj_faces_loops_reversed; | i_adj_polys->polys_reversed = adj_polys_loops_reversed; | ||||
| i_adj_faces->used += invalid_adj_faces->used; | i_adj_polys->used += invalid_adj_polys->used; | ||||
| MEM_freeN(invalid_adj_faces->faces); | MEM_freeN(invalid_adj_polys->polys); | ||||
| MEM_freeN(invalid_adj_faces->faces_reversed); | MEM_freeN(invalid_adj_polys->polys_reversed); | ||||
| MEM_freeN(invalid_adj_faces); | MEM_freeN(invalid_adj_polys); | ||||
| edge_adj_faces[invalid_edge_index] = i_adj_faces; | edge_adj_polys[invalid_edge_index] = i_adj_polys; | ||||
| /* Reset counter to continue. */ | /* Reset counter to continue. */ | ||||
| i = invalid_edge_index; | i = invalid_edge_index; | ||||
| } | } | ||||
| Context not available. | |||||
| /* Filter duplicate polys. */ | /* Filter duplicate polys. */ | ||||
| { | { | ||||
| ed = orig_medge; | ed = orig_medge; | ||||
| /* Iterate over edges and only check the faces around an edge for duplicates | /* Iterate over edges and only check the polys around an edge for duplicates | ||||
| * (performance optimization). */ | * (performance optimization). */ | ||||
| for (uint i = 0; i < numEdges; i++, ed++) { | for (uint i = 0; i < numEdges; i++, ed++) { | ||||
| if (edge_adj_faces_len[i] > 0) { | if (edge_adj_polys_len[i] > 0) { | ||||
| const OldEdgeFaceRef *adj_faces = edge_adj_faces[i]; | const EdgePolyLink *adj_polys = edge_adj_polys[i]; | ||||
| uint adj_len = adj_faces->faces_len; | uint adj_len = adj_polys->polys_len; | ||||
| /* Not that #adj_len doesn't need to equal edge_adj_faces_len anymore | /* Not that #adj_len doesn't need to equal edge_adj_polys_len anymore | ||||
| * because #adj_len is shared when a face got collapsed to an edge. */ | * because #adj_len is shared when a poly got collapsed to an edge. */ | ||||
| if (adj_len > 1) { | if (adj_len > 1) { | ||||
| /* For each face pair check if they have equal verts. */ | /* For each poly pair check if they have equal verts. */ | ||||
| for (uint j = 0; j < adj_len; j++) { | for (uint j = 0; j < adj_len; j++) { | ||||
| const uint face = adj_faces->faces[j]; | const uint poly = adj_polys->polys[j]; | ||||
| const int j_loopstart = orig_mpoly[face].loopstart; | const int j_loopstart = orig_mpoly[poly].loopstart; | ||||
| const int totloop = orig_mpoly[face].totloop; | const int totloop = orig_mpoly[poly].totloop; | ||||
| const uint j_first_v = vm[orig_mloop[j_loopstart].v]; | const uint j_first_v = vm[orig_mloop[j_loopstart].v]; | ||||
| for (uint k = j + 1; k < adj_len; k++) { | for (uint k = j + 1; k < adj_len; k++) { | ||||
| if (orig_mpoly[adj_faces->faces[k]].totloop != totloop) { | if (orig_mpoly[adj_polys->polys[k]].totloop != totloop) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Find first face first loop vert in second face loops. */ | /* Find first poly first loop vert in second poly loops. */ | ||||
| const int k_loopstart = orig_mpoly[adj_faces->faces[k]].loopstart; | const int k_loopstart = orig_mpoly[adj_polys->polys[k]].loopstart; | ||||
| int l; | int l; | ||||
| ml = orig_mloop + k_loopstart; | ml = orig_mloop + k_loopstart; | ||||
| for (l = 0; l < totloop && vm[ml->v] != j_first_v; l++, ml++) { | for (l = 0; l < totloop && vm[ml->v] != j_first_v; l++, ml++) { | ||||
| Context not available. | |||||
| continue; | continue; | ||||
| } | } | ||||
| /* Check if all following loops have equal verts. */ | /* Check if all following loops have equal verts. */ | ||||
| const bool reversed = adj_faces->faces_reversed[j] != adj_faces->faces_reversed[k]; | const bool reversed = adj_polys->polys_reversed[j] != adj_polys->polys_reversed[k]; | ||||
| const int count_dir = reversed ? -1 : 1; | const int count_dir = reversed ? -1 : 1; | ||||
| bool has_diff = false; | bool has_diff = false; | ||||
| ml = orig_mloop + j_loopstart; | ml = orig_mloop + j_loopstart; | ||||
| Context not available. | |||||
| m++, n += count_dir, ml++) { | m++, n += count_dir, ml++) { | ||||
| has_diff = has_diff || vm[ml->v] != vm[orig_mloop[k_loopstart + n % totloop].v]; | has_diff = has_diff || vm[ml->v] != vm[orig_mloop[k_loopstart + n % totloop].v]; | ||||
| } | } | ||||
| /* If the faces are equal, discard one (j). */ | /* If the polys are equal, discard one (j). */ | ||||
| if (!has_diff) { | if (!has_diff) { | ||||
| ml = orig_mloop + j_loopstart; | ml = orig_mloop + j_loopstart; | ||||
| uint del_loops = 0; | uint del_loops = 0; | ||||
| for (uint m = 0; m < totloop; m++, ml++) { | for (uint m = 0; m < totloop; m++, ml++) { | ||||
| const uint e = ml->e; | const uint e = ml->e; | ||||
| OldEdgeFaceRef *e_adj_faces = edge_adj_faces[e]; | EdgePolyLink *e_adj_polys = edge_adj_polys[e]; | ||||
| if (e_adj_faces) { | if (e_adj_polys) { | ||||
| uint face_index = j; | uint p_index = j; | ||||
| uint *e_adj_faces_faces = e_adj_faces->faces; | uint *e_adj_polys_polys = e_adj_polys->polys; | ||||
| bool *e_adj_faces_reversed = e_adj_faces->faces_reversed; | bool *e_adj_polys_reversed = e_adj_polys->polys_reversed; | ||||
| const uint faces_len = e_adj_faces->faces_len; | const uint polys_len = e_adj_polys->polys_len; | ||||
| if (e != i) { | if (e != i) { | ||||
| /* Find index of e in #adj_faces. */ | /* Find index of e in #adj_polys. */ | ||||
| for (face_index = 0; | for (p_index = 0; | ||||
| face_index < faces_len && e_adj_faces_faces[face_index] != face; | p_index < polys_len && e_adj_polys_polys[p_index] != poly; | ||||
| face_index++) { | p_index++) { | ||||
| /* Pass. */ | /* Pass. */ | ||||
| } | } | ||||
| /* If not found. */ | /* If not found. */ | ||||
| if (face_index == faces_len) { | if (p_index == polys_len) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* If we shrink #edge_adj_faces[i] we need to update this field. */ | /* If we shrink #edge_adj_polys[i] we need to update this field. */ | ||||
| adj_len--; | adj_len--; | ||||
| } | } | ||||
| memmove(e_adj_faces_faces + face_index, | memmove(e_adj_polys_polys + p_index, | ||||
| e_adj_faces_faces + face_index + 1, | e_adj_polys_polys + p_index + 1, | ||||
| (faces_len - face_index - 1) * sizeof(*e_adj_faces_faces)); | (polys_len - p_index - 1) * sizeof(*e_adj_polys_polys)); | ||||
| memmove(e_adj_faces_reversed + face_index, | memmove(e_adj_polys_reversed + p_index, | ||||
| e_adj_faces_reversed + face_index + 1, | e_adj_polys_reversed + p_index + 1, | ||||
| (faces_len - face_index - 1) * sizeof(*e_adj_faces_reversed)); | (polys_len - p_index - 1) * sizeof(*e_adj_polys_reversed)); | ||||
| e_adj_faces->faces_len--; | e_adj_polys->polys_len--; | ||||
| if (edge_adj_faces_len[e] > 0) { | if (edge_adj_polys_len[e] > 0) { | ||||
| edge_adj_faces_len[e]--; | edge_adj_polys_len[e]--; | ||||
| if (edge_adj_faces_len[e] == 0) { | if (edge_adj_polys_len[e] == 0) { | ||||
| e_adj_faces->used--; | e_adj_polys->used--; | ||||
| edge_adj_faces[e] = NULL; | edge_adj_polys[e] = NULL; | ||||
| } | } | ||||
| } | } | ||||
| else if (e_adj_faces->used > 1) { | else if (e_adj_polys->used > 1) { | ||||
| for (uint n = 0; n < numEdges; n++) { | for (uint n = 0; n < numEdges; n++) { | ||||
| if (edge_adj_faces[n] == e_adj_faces && edge_adj_faces_len[n] > 0) { | if (edge_adj_polys[n] == e_adj_polys && edge_adj_polys_len[n] > 0) { | ||||
| edge_adj_faces_len[n]--; | edge_adj_polys_len[n]--; | ||||
| if (edge_adj_faces_len[n] == 0) { | if (edge_adj_polys_len[n] == 0) { | ||||
| edge_adj_faces[n]->used--; | edge_adj_polys[n]->used--; | ||||
| edge_adj_faces[n] = NULL; | edge_adj_polys[n] = NULL; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| Context not available. | |||||
| del_loops++; | del_loops++; | ||||
| } | } | ||||
| } | } | ||||
| if (do_shell) { | if (sctx->do_shell) { | ||||
| numNewPolys -= 2; | result->numPolys -= 2; | ||||
| numNewLoops -= 2 * (uint)del_loops; | result->numLoops -= 2 * (uint)del_loops; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| /* Create #NewEdgeRef array. */ | /* Create #SolidifyEdge array. */ | ||||
| { | { | ||||
| ed = orig_medge; | ed = orig_medge; | ||||
| for (uint i = 0; i < numEdges; i++, ed++) { | for (uint i = 0; i < numEdges; i++, ed++) { | ||||
| const uint v1 = vm[ed->v1]; | const uint v1 = vm[ed->v1]; | ||||
| const uint v2 = vm[ed->v2]; | const uint v2 = vm[ed->v2]; | ||||
| if (edge_adj_faces_len[i] > 0) { | if (edge_adj_polys_len[i] > 0) { | ||||
| sub_v3_v3v3(edgedir, orig_mvert_co[v2], orig_mvert_co[v1]); | sub_v3_v3v3(edgedir, orig_mvert_co[v2], orig_mvert_co[v1]); | ||||
| mul_v3_fl(edgedir, 1.0f / orig_edge_lengths[i]); | mul_v3_fl(edgedir, 1.0f / orig_edge_lengths[i]); | ||||
| OldEdgeFaceRef *adj_faces = edge_adj_faces[i]; | EdgePolyLink *adj_polys = edge_adj_polys[i]; | ||||
| const uint adj_len = adj_faces->faces_len; | const uint adj_len = adj_polys->polys_len; | ||||
| const uint *adj_faces_faces = adj_faces->faces; | const uint *adj_polys_polys = adj_polys->polys; | ||||
| const bool *adj_faces_reversed = adj_faces->faces_reversed; | const bool *adj_polys_reversed = adj_polys->polys_reversed; | ||||
| uint new_edges_len = 0; | uint new_edges_len = 0; | ||||
| FaceKeyPair *sorted_faces = MEM_malloc_arrayN( | PolyKeyPair *sorted_polys = MEM_malloc_arrayN( | ||||
| adj_len, sizeof(*sorted_faces), "sorted_faces in solidify"); | adj_len, sizeof(*sorted_polys), "sorted_polys in solidify"); | ||||
| if (adj_len > 1) { | if (adj_len > 1) { | ||||
| new_edges_len = adj_len; | new_edges_len = adj_len; | ||||
| /* Get keys for sorting. */ | /* Get keys for sorting. */ | ||||
| float ref_nor[3] = {0, 0, 0}; | float ref_nor[3] = {0, 0, 0}; | ||||
| float nor[3]; | float nor[3]; | ||||
| for (uint j = 0; j < adj_len; j++) { | for (uint j = 0; j < adj_len; j++) { | ||||
| const bool reverse = adj_faces_reversed[j]; | const bool reverse = adj_polys_reversed[j]; | ||||
| const uint face_i = adj_faces_faces[j]; | const uint poly_i = adj_polys_polys[j]; | ||||
| if (reverse) { | if (reverse) { | ||||
| negate_v3_v3(nor, poly_nors[face_i]); | negate_v3_v3(nor, poly_nors[poly_i]); | ||||
| } | } | ||||
| else { | else { | ||||
| copy_v3_v3(nor, poly_nors[face_i]); | copy_v3_v3(nor, poly_nors[poly_i]); | ||||
| } | } | ||||
| float d = 1; | float d = 1; | ||||
| if (orig_mpoly[face_i].totloop > 3) { | if (orig_mpoly[poly_i].totloop > 3) { | ||||
| d = project_v3_v3(nor, edgedir); | d = project_v3_v3(nor, edgedir); | ||||
| if (LIKELY(d != 0)) { | if (LIKELY(d != 0)) { | ||||
| d = normalize_v3(nor); | d = normalize_v3(nor); | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| if (UNLIKELY(d == 0.0f)) { | if (UNLIKELY(d == 0.0f)) { | ||||
| sorted_faces[j].angle = 0.0f; | sorted_polys[j].angle = 0.0f; | ||||
| } | } | ||||
| else if (j == 0) { | else if (j == 0) { | ||||
| copy_v3_v3(ref_nor, nor); | copy_v3_v3(ref_nor, nor); | ||||
| sorted_faces[j].angle = 0.0f; | sorted_polys[j].angle = 0.0f; | ||||
| } | } | ||||
| else { | else { | ||||
| float angle = angle_signed_on_axis_normalized_v3v3_v3(nor, ref_nor, edgedir); | float angle = angle_signed_on_axis_normalized_v3v3_v3(nor, ref_nor, edgedir); | ||||
| sorted_faces[j].angle = -angle; | sorted_polys[j].angle = -angle; | ||||
| } | } | ||||
| sorted_faces[j].face = face_sides_arr + adj_faces_faces[j] * 2 + | sorted_polys[j].poly = result->polys + adj_polys_polys[j] * 2 + | ||||
| (adj_faces_reversed[j] ? 1 : 0); | (adj_polys_reversed[j] ? 1 : 0); | ||||
| } | } | ||||
| /* Sort faces by order around the edge (keep order in faces, | /* Sort polys by order around the edge (keep order in polys, | ||||
| * reversed and face_angles the same). */ | * reversed and poly_angles the same). */ | ||||
| qsort(sorted_faces, adj_len, sizeof(*sorted_faces), comp_float_int_pair); | qsort(sorted_polys, adj_len, sizeof(*sorted_polys), comp_float_int_pair); | ||||
| } | } | ||||
| else { | else { | ||||
| new_edges_len = 2; | new_edges_len = 2; | ||||
| sorted_faces[0].face = face_sides_arr + adj_faces_faces[0] * 2 + | sorted_polys[0].poly = result->polys + adj_polys_polys[0] * 2 + | ||||
| (adj_faces_reversed[0] ? 1 : 0); | (adj_polys_reversed[0] ? 1 : 0); | ||||
| if (do_rim) { | if (sctx->do_rim) { | ||||
| /* Only add the loops parallel to the edge for now. */ | /* Only add the loops parallel to the edge for now. */ | ||||
| numNewLoops += 2; | result->numLoops += 2; | ||||
| numNewPolys++; | result->numPolys++; | ||||
| } | } | ||||
| } | } | ||||
| /* Create a list of new edges and fill it. */ | /* Create a list of new edges and fill it. */ | ||||
| NewEdgeRef **new_edges = MEM_malloc_arrayN( | SolidifyEdge **new_edges = MEM_malloc_arrayN( | ||||
| new_edges_len + 1, sizeof(*new_edges), "new_edges in solidify"); | new_edges_len + 1, sizeof(*new_edges), "new_edges in solidify"); | ||||
| new_edges[new_edges_len] = NULL; | new_edges[new_edges_len] = NULL; | ||||
| NewFaceRef *faces[2]; | SolidifyPoly *polys[2]; | ||||
| for (uint j = 0; j < new_edges_len; j++) { | for (uint j = 0; j < new_edges_len; j++) { | ||||
| float angle; | float angle; | ||||
| if (adj_len > 1) { | if (adj_len > 1) { | ||||
| const uint next_j = j + 1 == adj_len ? 0 : j + 1; | const uint next_j = j + 1 == adj_len ? 0 : j + 1; | ||||
| faces[0] = sorted_faces[j].face; | polys[0] = sorted_polys[j].poly; | ||||
| faces[1] = sorted_faces[next_j].face->reversed ? sorted_faces[next_j].face - 1 : | polys[1] = sorted_polys[next_j].poly->reversed ? sorted_polys[next_j].poly - 1 : | ||||
| sorted_faces[next_j].face + 1; | sorted_polys[next_j].poly + 1; | ||||
| angle = sorted_faces[next_j].angle - sorted_faces[j].angle; | angle = sorted_polys[next_j].angle - sorted_polys[j].angle; | ||||
| if (angle < 0) { | if (angle < 0) { | ||||
| angle += 2 * M_PI; | angle += 2 * M_PI; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| faces[0] = sorted_faces[0].face->reversed ? sorted_faces[0].face - j : | polys[0] = sorted_polys[0].poly->reversed ? sorted_polys[0].poly - j : | ||||
| sorted_faces[0].face + j; | sorted_polys[0].poly + j; | ||||
| faces[1] = NULL; | polys[1] = NULL; | ||||
| angle = 0; | angle = 0; | ||||
| } | } | ||||
| NewEdgeRef *edge_data = MEM_mallocN(sizeof(*edge_data), "edge_data in solidify"); | SolidifyEdge *edge_data = MEM_mallocN(sizeof(*edge_data), "edge_data in solidify"); | ||||
| uint edge_data_edge_index = MOD_SOLIDIFY_EMPTY_TAG; | uint edge_data_edge_index = MOD_SOLIDIFY_EMPTY_TAG; | ||||
| if (do_shell || (adj_len == 1 && do_rim)) { | if (sctx->do_shell || (adj_len == 1 && sctx->do_rim)) { | ||||
| edge_data_edge_index = 0; | edge_data_edge_index = 0; | ||||
| } | } | ||||
| *edge_data = (NewEdgeRef){.old_edge = i, | *edge_data = (SolidifyEdge){.orig_edge = i, | ||||
| .faces = {faces[0], faces[1]}, | .polys = {polys[0], polys[1]}, | ||||
| .link_edge_groups = {NULL, NULL}, | .link_corners = {NULL, NULL}, | ||||
| .angle = angle, | .angle = angle, | ||||
| .new_edge = edge_data_edge_index}; | .new_edge = edge_data_edge_index}; | ||||
| new_edges[j] = edge_data; | new_edges[j] = edge_data; | ||||
| for (uint k = 0; k < 2; k++) { | for (uint k = 0; k < 2; k++) { | ||||
| if (faces[k] != NULL) { | if (polys[k] != NULL) { | ||||
| ml = orig_mloop + faces[k]->face->loopstart; | ml = orig_mloop + polys[k]->poly->loopstart; | ||||
| for (int l = 0; l < faces[k]->face->totloop; l++, ml++) { | for (int l = 0; l < polys[k]->poly->totloop; l++, ml++) { | ||||
| if (edge_adj_faces[ml->e] == edge_adj_faces[i]) { | if (edge_adj_polys[ml->e] == edge_adj_polys[i]) { | ||||
| if (ml->e != i && orig_edge_data_arr[ml->e] == NULL) { | if (ml->e != i && result->edges[ml->e] == NULL) { | ||||
| orig_edge_data_arr[ml->e] = new_edges; | result->edges[ml->e] = new_edges; | ||||
| } | } | ||||
| faces[k]->link_edges[l] = edge_data; | polys[k]->link_edges[l] = edge_data; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(sorted_faces); | MEM_freeN(sorted_polys); | ||||
| orig_edge_data_arr[i] = new_edges; | result->edges[i] = new_edges; | ||||
| if (do_shell || (adj_len == 1 && do_rim)) { | if (sctx->do_shell || (adj_len == 1 && sctx->do_rim)) { | ||||
| numNewEdges += new_edges_len; | result->numEdges += new_edges_len; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| for (uint i = 0; i < numEdges; i++) { | for (uint i = 0; i < numEdges; i++) { | ||||
| if (edge_adj_faces[i]) { | if (edge_adj_polys[i]) { | ||||
| if (edge_adj_faces[i]->used > 1) { | if (edge_adj_polys[i]->used > 1) { | ||||
| edge_adj_faces[i]->used--; | edge_adj_polys[i]->used--; | ||||
| } | } | ||||
| else { | else { | ||||
| MEM_freeN(edge_adj_faces[i]->faces); | MEM_freeN(edge_adj_polys[i]->polys); | ||||
| MEM_freeN(edge_adj_faces[i]->faces_reversed); | MEM_freeN(edge_adj_polys[i]->polys_reversed); | ||||
| MEM_freeN(edge_adj_faces[i]); | MEM_freeN(edge_adj_polys[i]); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(edge_adj_faces); | MEM_freeN(edge_adj_polys); | ||||
| } | } | ||||
| /* Create sorted edge groups for every vert. */ | /* Create sorted #SolidifyCorner arrays for every vert. */ | ||||
| { | { | ||||
| OldVertEdgeRef **adj_edges_ptr = vert_adj_edges; | VertEdgeLink **adj_edges_ptr = vert_adj_edges; | ||||
| for (uint i = 0; i < numVerts; i++, adj_edges_ptr++) { | for (uint i = 0; i < numVerts; i++, adj_edges_ptr++) { | ||||
| if (*adj_edges_ptr != NULL && (*adj_edges_ptr)->edges_len >= 2) { | if (*adj_edges_ptr != NULL && (*adj_edges_ptr)->edges_len >= 2) { | ||||
| EdgeGroup *edge_groups; | SolidifyCorner *corners; | ||||
| int eg_index = -1; | int corner_index = -1; | ||||
| bool contains_long_groups = false; | bool contains_long_groups = false; | ||||
| uint topo_groups = 0; | uint topo_groups = 0; | ||||
| Context not available. | |||||
| uint unassigned_edges_len = 0; | uint unassigned_edges_len = 0; | ||||
| for (uint j = 0; j < tot_adj_edges; j++) { | for (uint j = 0; j < tot_adj_edges; j++) { | ||||
| NewEdgeRef **new_edges = orig_edge_data_arr[adj_edges[j]]; | SolidifyEdge **new_edges = result->edges[adj_edges[j]]; | ||||
| /* TODO check where the null pointer come from, | /* TODO check where the null pointer come from, | ||||
| * because there should not be any... */ | * because there should not be any... */ | ||||
| if (new_edges) { | if (new_edges) { | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| NewEdgeRef **unassigned_edges = MEM_malloc_arrayN( | SolidifyEdge **unassigned_edges = MEM_malloc_arrayN( | ||||
| unassigned_edges_len, sizeof(*unassigned_edges), "unassigned_edges in solidify"); | unassigned_edges_len, sizeof(*unassigned_edges), "unassigned_edges in solidify"); | ||||
| for (uint j = 0, k = 0; j < tot_adj_edges; j++) { | for (uint j = 0, k = 0; j < tot_adj_edges; j++) { | ||||
| NewEdgeRef **new_edges = orig_edge_data_arr[adj_edges[j]]; | SolidifyEdge **new_edges = result->edges[adj_edges[j]]; | ||||
| if (new_edges) { | if (new_edges) { | ||||
| while (*new_edges) { | while (*new_edges) { | ||||
| unassigned_edges[k++] = *new_edges; | unassigned_edges[k++] = *new_edges; | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| /* An edge group will always contain min 2 edges | /* A corner will always contain min 2 edges | ||||
| * so max edge group count can be calculated. */ | * so max corner count can be calculated. */ | ||||
| uint edge_groups_len = unassigned_edges_len / 2; | uint corners_len = unassigned_edges_len / 2; | ||||
| edge_groups = MEM_calloc_arrayN( | corners = MEM_calloc_arrayN(corners_len + 1, sizeof(*corners), "corners in solidify"); | ||||
| edge_groups_len + 1, sizeof(*edge_groups), "edge_groups in solidify"); | |||||
| uint assigned_edges_len = 0; | uint assigned_edges_len = 0; | ||||
| NewEdgeRef *found_edge = NULL; | SolidifyEdge *found_edge = NULL; | ||||
| uint found_edge_index = 0; | uint found_edge_index = 0; | ||||
| bool insert_at_start = false; | bool insert_at_start = false; | ||||
| uint eg_capacity = 5; | uint eg_capacity = 5; | ||||
| NewFaceRef *eg_track_faces[2] = {NULL, NULL}; | SolidifyPoly *eg_track_polys[2] = {NULL, NULL}; | ||||
| NewFaceRef *last_open_edge_track = NULL; | SolidifyPoly *last_open_edge_track = NULL; | ||||
| while (assigned_edges_len < unassigned_edges_len) { | while (assigned_edges_len < unassigned_edges_len) { | ||||
| found_edge = NULL; | found_edge = NULL; | ||||
| insert_at_start = false; | insert_at_start = false; | ||||
| if (eg_index >= 0 && edge_groups[eg_index].edges_len == 0) { | if (corner_index >= 0 && corners[corner_index].edges_len == 0) { | ||||
| /* Called every time a new group was started in the last iteration. */ | /* Called every time a new group was started in the last iteration. */ | ||||
| /* Find an unused edge to start the next group | /* Find an unused edge to start the next group | ||||
| * and setup variables to start creating it. */ | * and setup variables to start creating it. */ | ||||
| uint j = 0; | uint j = 0; | ||||
| NewEdgeRef *edge = NULL; | SolidifyEdge *edge = NULL; | ||||
| while (!edge && j < unassigned_edges_len) { | while (!edge && j < unassigned_edges_len) { | ||||
| edge = unassigned_edges[j++]; | edge = unassigned_edges[j++]; | ||||
| if (edge && last_open_edge_track && | if (edge && last_open_edge_track && | ||||
| (edge->faces[0] != last_open_edge_track || edge->faces[1] != NULL)) { | (edge->polys[0] != last_open_edge_track || edge->polys[1] != NULL)) { | ||||
| edge = NULL; | edge = NULL; | ||||
| } | } | ||||
| } | } | ||||
| if (!edge && last_open_edge_track) { | if (!edge && last_open_edge_track) { | ||||
| topo_groups++; | topo_groups++; | ||||
| last_open_edge_track = NULL; | last_open_edge_track = NULL; | ||||
| edge_groups[eg_index].topo_group++; | corners[corner_index].topo_group++; | ||||
| j = 0; | j = 0; | ||||
| while (!edge && j < unassigned_edges_len) { | while (!edge && j < unassigned_edges_len) { | ||||
| edge = unassigned_edges[j++]; | edge = unassigned_edges[j++]; | ||||
| } | } | ||||
| } | } | ||||
| else if (!last_open_edge_track && eg_index > 0) { | else if (!last_open_edge_track && corner_index > 0) { | ||||
| topo_groups++; | topo_groups++; | ||||
| edge_groups[eg_index].topo_group++; | corners[corner_index].topo_group++; | ||||
| } | } | ||||
| BLI_assert(edge != NULL); | BLI_assert(edge != NULL); | ||||
| found_edge_index = j - 1; | found_edge_index = j - 1; | ||||
| found_edge = edge; | found_edge = edge; | ||||
| if (!last_open_edge_track && vm[orig_medge[edge->old_edge].v1] == i) { | if (!last_open_edge_track && vm[orig_medge[edge->orig_edge].v1] == i) { | ||||
| eg_track_faces[0] = edge->faces[0]; | eg_track_polys[0] = edge->polys[0]; | ||||
| eg_track_faces[1] = edge->faces[1]; | eg_track_polys[1] = edge->polys[1]; | ||||
| if (edge->faces[1] == NULL) { | if (edge->polys[1] == NULL) { | ||||
| last_open_edge_track = edge->faces[0]->reversed ? edge->faces[0] - 1 : | last_open_edge_track = edge->polys[0]->reversed ? edge->polys[0] - 1 : | ||||
| edge->faces[0] + 1; | edge->polys[0] + 1; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| eg_track_faces[0] = edge->faces[1]; | eg_track_polys[0] = edge->polys[1]; | ||||
| eg_track_faces[1] = edge->faces[0]; | eg_track_polys[1] = edge->polys[0]; | ||||
| } | } | ||||
| } | } | ||||
| else if (eg_index >= 0) { | else if (corner_index >= 0) { | ||||
| NewEdgeRef **edge_ptr = unassigned_edges; | SolidifyEdge **edge_ptr = unassigned_edges; | ||||
| for (found_edge_index = 0; found_edge_index < unassigned_edges_len; | for (found_edge_index = 0; found_edge_index < unassigned_edges_len; | ||||
| found_edge_index++, edge_ptr++) { | found_edge_index++, edge_ptr++) { | ||||
| if (*edge_ptr) { | if (*edge_ptr) { | ||||
| NewEdgeRef *edge = *edge_ptr; | SolidifyEdge *edge = *edge_ptr; | ||||
| if (edge->faces[0] == eg_track_faces[1]) { | if (edge->polys[0] == eg_track_polys[1]) { | ||||
| insert_at_start = false; | insert_at_start = false; | ||||
| eg_track_faces[1] = edge->faces[1]; | eg_track_polys[1] = edge->polys[1]; | ||||
| found_edge = edge; | found_edge = edge; | ||||
| if (edge->faces[1] == NULL) { | if (edge->polys[1] == NULL) { | ||||
| edge_groups[eg_index].is_orig_closed = false; | corners[corner_index].is_orig_closed = false; | ||||
| last_open_edge_track = edge->faces[0]->reversed ? edge->faces[0] - 1 : | last_open_edge_track = edge->polys[0]->reversed ? edge->polys[0] - 1 : | ||||
| edge->faces[0] + 1; | edge->polys[0] + 1; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| else if (edge->faces[0] == eg_track_faces[0]) { | else if (edge->polys[0] == eg_track_polys[0]) { | ||||
| insert_at_start = true; | insert_at_start = true; | ||||
| eg_track_faces[0] = edge->faces[1]; | eg_track_polys[0] = edge->polys[1]; | ||||
| found_edge = edge; | found_edge = edge; | ||||
| if (edge->faces[1] == NULL) { | if (edge->polys[1] == NULL) { | ||||
| edge_groups[eg_index].is_orig_closed = false; | corners[corner_index].is_orig_closed = false; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| else if (edge->faces[1] != NULL) { | else if (edge->polys[1] != NULL) { | ||||
| if (edge->faces[1] == eg_track_faces[1]) { | if (edge->polys[1] == eg_track_polys[1]) { | ||||
| insert_at_start = false; | insert_at_start = false; | ||||
| eg_track_faces[1] = edge->faces[0]; | eg_track_polys[1] = edge->polys[0]; | ||||
| found_edge = edge; | found_edge = edge; | ||||
| break; | break; | ||||
| } | } | ||||
| else if (edge->faces[1] == eg_track_faces[0]) { | else if (edge->polys[1] == eg_track_polys[0]) { | ||||
| insert_at_start = true; | insert_at_start = true; | ||||
| eg_track_faces[0] = edge->faces[0]; | eg_track_polys[0] = edge->polys[0]; | ||||
| found_edge = edge; | found_edge = edge; | ||||
| break; | break; | ||||
| } | } | ||||
| Context not available. | |||||
| if (found_edge) { | if (found_edge) { | ||||
| unassigned_edges[found_edge_index] = NULL; | unassigned_edges[found_edge_index] = NULL; | ||||
| assigned_edges_len++; | assigned_edges_len++; | ||||
| const uint needed_capacity = edge_groups[eg_index].edges_len + 1; | const uint needed_capacity = corners[corner_index].edges_len + 1; | ||||
| if (needed_capacity > eg_capacity) { | if (needed_capacity > eg_capacity) { | ||||
| eg_capacity = needed_capacity + 1; | eg_capacity = needed_capacity + 1; | ||||
| NewEdgeRef **new_eg = MEM_calloc_arrayN( | SolidifyEdge **new_eg = MEM_calloc_arrayN( | ||||
| eg_capacity, sizeof(*new_eg), "edge_group realloc in solidify"); | eg_capacity, sizeof(*new_eg), "corner realloc in solidify"); | ||||
| if (insert_at_start) { | if (insert_at_start) { | ||||
| memcpy(new_eg + 1, | memcpy(new_eg + 1, | ||||
| edge_groups[eg_index].edges, | corners[corner_index].edges, | ||||
| edge_groups[eg_index].edges_len * sizeof(*new_eg)); | corners[corner_index].edges_len * sizeof(*new_eg)); | ||||
| } | } | ||||
| else { | else { | ||||
| memcpy(new_eg, | memcpy(new_eg, | ||||
| edge_groups[eg_index].edges, | corners[corner_index].edges, | ||||
| edge_groups[eg_index].edges_len * sizeof(*new_eg)); | corners[corner_index].edges_len * sizeof(*new_eg)); | ||||
| } | } | ||||
| MEM_freeN(edge_groups[eg_index].edges); | MEM_freeN(corners[corner_index].edges); | ||||
| edge_groups[eg_index].edges = new_eg; | corners[corner_index].edges = new_eg; | ||||
| } | } | ||||
| else if (insert_at_start) { | else if (insert_at_start) { | ||||
| memmove(edge_groups[eg_index].edges + 1, | memmove(corners[corner_index].edges + 1, | ||||
| edge_groups[eg_index].edges, | corners[corner_index].edges, | ||||
| edge_groups[eg_index].edges_len * sizeof(*edge_groups[eg_index].edges)); | corners[corner_index].edges_len * sizeof(*corners[corner_index].edges)); | ||||
| } | } | ||||
| edge_groups[eg_index].edges[insert_at_start ? 0 : edge_groups[eg_index].edges_len] = | corners[corner_index].edges[insert_at_start ? 0 : corners[corner_index].edges_len] = | ||||
| found_edge; | found_edge; | ||||
| edge_groups[eg_index].edges_len++; | corners[corner_index].edges_len++; | ||||
| if (edge_groups[eg_index].edges[edge_groups[eg_index].edges_len - 1]->faces[1] != | if (corners[corner_index].edges[corners[corner_index].edges_len - 1]->polys[1] != NULL) { | ||||
| NULL) { | |||||
| last_open_edge_track = NULL; | last_open_edge_track = NULL; | ||||
| } | } | ||||
| if (edge_groups[eg_index].edges_len > 3) { | if (corners[corner_index].edges_len > 3) { | ||||
| contains_long_groups = true; | contains_long_groups = true; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* called on first iteration to clean up the eg_index = -1 and start the first group, | /* called on first iteration to clean up the corner_index = -1 and start the first group, | ||||
| * or when the current group is found to be complete (no new found_edge) */ | * or when the current group is found to be complete (no new found_edge) */ | ||||
| eg_index++; | corner_index++; | ||||
| BLI_assert(eg_index < edge_groups_len); | BLI_assert(corner_index < corners_len); | ||||
| eg_capacity = 5; | eg_capacity = 5; | ||||
| NewEdgeRef **edges = MEM_calloc_arrayN( | SolidifyEdge **edges = MEM_calloc_arrayN( | ||||
| eg_capacity, sizeof(*edges), "edge_group in solidify"); | eg_capacity, sizeof(*edges), "corner in solidify"); | ||||
| edge_groups[eg_index] = (EdgeGroup){ | corners[corner_index] = (SolidifyCorner){ | ||||
| .valid = true, | .valid = true, | ||||
| .edges = edges, | .edges = edges, | ||||
| .edges_len = 0, | .edges_len = 0, | ||||
| .open_face_edge = MOD_SOLIDIFY_EMPTY_TAG, | .open_poly_edge = MOD_SOLIDIFY_EMPTY_TAG, | ||||
| .is_orig_closed = true, | .is_orig_closed = true, | ||||
| .is_even_split = false, | .is_even_split = false, | ||||
| .split = 0, | .split = 0, | ||||
| Context not available. | |||||
| .no = {0.0f, 0.0f, 0.0f}, | .no = {0.0f, 0.0f, 0.0f}, | ||||
| .new_vert = MOD_SOLIDIFY_EMPTY_TAG, | .new_vert = MOD_SOLIDIFY_EMPTY_TAG, | ||||
| }; | }; | ||||
| eg_track_faces[0] = NULL; | eg_track_polys[0] = NULL; | ||||
| eg_track_faces[1] = NULL; | eg_track_polys[1] = NULL; | ||||
| } | } | ||||
| } | } | ||||
| /* #eg_index is the number of groups from here on. */ | /* #corner_index is the number of groups from here on. */ | ||||
| eg_index++; | corner_index++; | ||||
| /* #topo_groups is the number of topo groups from here on. */ | /* #topo_groups is the number of topo groups from here on. */ | ||||
| topo_groups++; | topo_groups++; | ||||
| MEM_freeN(unassigned_edges); | MEM_freeN(unassigned_edges); | ||||
| /* TODO reshape the edge_groups array to its actual size | /* TODO reshape the corners array to its actual size | ||||
| * after writing is finished to save on memory. */ | * after writing is finished to save on memory. */ | ||||
| } | } | ||||
| Context not available. | |||||
| uint splits = 0; | uint splits = 0; | ||||
| if (contains_long_groups) { | if (contains_long_groups) { | ||||
| uint add_index = 0; | uint add_index = 0; | ||||
| for (uint j = 0; j < eg_index; j++) { | for (uint j = 0; j < corner_index; j++) { | ||||
| const uint edges_len = edge_groups[j + add_index].edges_len; | const uint edges_len = corners[j + add_index].edges_len; | ||||
| if (edges_len > 3) { | if (edges_len > 3) { | ||||
| bool has_doubles = false; | bool has_doubles = false; | ||||
| bool *doubles = MEM_calloc_arrayN( | bool *doubles = MEM_calloc_arrayN( | ||||
| edges_len, sizeof(*doubles), "doubles in solidify"); | edges_len, sizeof(*doubles), "doubles in solidify"); | ||||
| EdgeGroup g = edge_groups[j + add_index]; | SolidifyCorner g = corners[j + add_index]; | ||||
| for (uint k = 0; k < edges_len; k++) { | for (uint k = 0; k < edges_len; k++) { | ||||
| for (uint l = k + 1; l < edges_len; l++) { | for (uint l = k + 1; l < edges_len; l++) { | ||||
| if (g.edges[k]->old_edge == g.edges[l]->old_edge) { | if (g.edges[k]->orig_edge == g.edges[l]->orig_edge) { | ||||
| doubles[k] = true; | doubles[k] = true; | ||||
| doubles[l] = true; | doubles[l] = true; | ||||
| has_doubles = true; | has_doubles = true; | ||||
| Context not available. | |||||
| if (last_split != -1) { | if (last_split != -1) { | ||||
| /* Override g on first split (no insert). */ | /* Override g on first split (no insert). */ | ||||
| if (prior_splits != splits) { | if (prior_splits != splits) { | ||||
| memmove(edge_groups + j + add_index + 1, | memmove(corners + j + add_index + 1, | ||||
| edge_groups + j + add_index, | corners + j + add_index, | ||||
| ((uint)eg_index - j) * sizeof(*edge_groups)); | ((uint)corner_index - j) * sizeof(*corners)); | ||||
| add_index++; | add_index++; | ||||
| } | } | ||||
| if (last_split > split) { | if (last_split > split) { | ||||
| const uint size = (split + edges_len) - (uint)last_split; | const uint size = (split + edges_len) - (uint)last_split; | ||||
| NewEdgeRef **edges = MEM_malloc_arrayN( | SolidifyEdge **edges = MEM_malloc_arrayN( | ||||
| size, sizeof(*edges), "edge_group split in solidify"); | size, sizeof(*edges), "corner split in solidify"); | ||||
| memcpy(edges, | memcpy(edges, | ||||
| g.edges + last_split, | g.edges + last_split, | ||||
| (edges_len - (uint)last_split) * sizeof(*edges)); | (edges_len - (uint)last_split) * sizeof(*edges)); | ||||
| memcpy(edges + (edges_len - (uint)last_split), | memcpy(edges + (edges_len - (uint)last_split), | ||||
| g.edges, | g.edges, | ||||
| split * sizeof(*edges)); | split * sizeof(*edges)); | ||||
| edge_groups[j + add_index] = (EdgeGroup){ | corners[j + add_index] = (SolidifyCorner){ | ||||
| .valid = true, | .valid = true, | ||||
| .edges = edges, | .edges = edges, | ||||
| .edges_len = size, | .edges_len = size, | ||||
| .open_face_edge = MOD_SOLIDIFY_EMPTY_TAG, | .open_poly_edge = MOD_SOLIDIFY_EMPTY_TAG, | ||||
| .is_orig_closed = g.is_orig_closed, | .is_orig_closed = g.is_orig_closed, | ||||
| .is_even_split = is_even_split, | .is_even_split = is_even_split, | ||||
| .split = add_index - prior_index + 1 + (uint)!g.is_orig_closed, | .split = add_index - prior_index + 1 + (uint)!g.is_orig_closed, | ||||
| Context not available. | |||||
| } | } | ||||
| else { | else { | ||||
| const uint size = split - (uint)last_split; | const uint size = split - (uint)last_split; | ||||
| NewEdgeRef **edges = MEM_malloc_arrayN( | SolidifyEdge **edges = MEM_malloc_arrayN( | ||||
| size, sizeof(*edges), "edge_group split in solidify"); | size, sizeof(*edges), "corner split in solidify"); | ||||
| memcpy(edges, g.edges + last_split, size * sizeof(*edges)); | memcpy(edges, g.edges + last_split, size * sizeof(*edges)); | ||||
| edge_groups[j + add_index] = (EdgeGroup){ | corners[j + add_index] = (SolidifyCorner){ | ||||
| .valid = true, | .valid = true, | ||||
| .edges = edges, | .edges = edges, | ||||
| .edges_len = size, | .edges_len = size, | ||||
| .open_face_edge = MOD_SOLIDIFY_EMPTY_TAG, | .open_poly_edge = MOD_SOLIDIFY_EMPTY_TAG, | ||||
| .is_orig_closed = g.is_orig_closed, | .is_orig_closed = g.is_orig_closed, | ||||
| .is_even_split = is_even_split, | .is_even_split = is_even_split, | ||||
| .split = add_index - prior_index + 1 + (uint)!g.is_orig_closed, | .split = add_index - prior_index + 1 + (uint)!g.is_orig_closed, | ||||
| Context not available. | |||||
| if (first_split != -1) { | if (first_split != -1) { | ||||
| if (!g.is_orig_closed) { | if (!g.is_orig_closed) { | ||||
| if (prior_splits != splits) { | if (prior_splits != splits) { | ||||
| memmove(edge_groups + (j + prior_index + 1), | memmove(corners + (j + prior_index + 1), | ||||
| edge_groups + (j + prior_index), | corners + (j + prior_index), | ||||
| ((uint)eg_index + add_index - (j + prior_index)) * | ((uint)corner_index + add_index - (j + prior_index)) * | ||||
| sizeof(*edge_groups)); | sizeof(*corners)); | ||||
| memmove(edge_groups + (j + add_index + 2), | memmove(corners + (j + add_index + 2), | ||||
| edge_groups + (j + add_index + 1), | corners + (j + add_index + 1), | ||||
| ((uint)eg_index - j) * sizeof(*edge_groups)); | ((uint)corner_index - j) * sizeof(*corners)); | ||||
| add_index++; | add_index++; | ||||
| } | } | ||||
| else { | else { | ||||
| memmove(edge_groups + (j + add_index + 2), | memmove(corners + (j + add_index + 2), | ||||
| edge_groups + (j + add_index + 1), | corners + (j + add_index + 1), | ||||
| ((uint)eg_index - j - 1) * sizeof(*edge_groups)); | ((uint)corner_index - j - 1) * sizeof(*corners)); | ||||
| } | } | ||||
| NewEdgeRef **edges = MEM_malloc_arrayN( | SolidifyEdge **edges = MEM_malloc_arrayN( | ||||
| (uint)first_split, sizeof(*edges), "edge_group split in solidify"); | (uint)first_split, sizeof(*edges), "corner split in solidify"); | ||||
| memcpy(edges, g.edges, (uint)first_split * sizeof(*edges)); | memcpy(edges, g.edges, (uint)first_split * sizeof(*edges)); | ||||
| edge_groups[j + prior_index] = (EdgeGroup){ | corners[j + prior_index] = (SolidifyCorner){ | ||||
| .valid = true, | .valid = true, | ||||
| .edges = edges, | .edges = edges, | ||||
| .edges_len = (uint)first_split, | .edges_len = (uint)first_split, | ||||
| .open_face_edge = MOD_SOLIDIFY_EMPTY_TAG, | .open_poly_edge = MOD_SOLIDIFY_EMPTY_TAG, | ||||
| .is_orig_closed = g.is_orig_closed, | .is_orig_closed = g.is_orig_closed, | ||||
| .is_even_split = first_even_split, | .is_even_split = first_even_split, | ||||
| .split = 1, | .split = 1, | ||||
| Context not available. | |||||
| splits++; | splits++; | ||||
| edges = MEM_malloc_arrayN(edges_len - (uint)last_split, | edges = MEM_malloc_arrayN(edges_len - (uint)last_split, | ||||
| sizeof(*edges), | sizeof(*edges), | ||||
| "edge_group split in solidify"); | "corner split in solidify"); | ||||
| memcpy(edges, | memcpy(edges, | ||||
| g.edges + last_split, | g.edges + last_split, | ||||
| (edges_len - (uint)last_split) * sizeof(*edges)); | (edges_len - (uint)last_split) * sizeof(*edges)); | ||||
| edge_groups[j + add_index] = (EdgeGroup){ | corners[j + add_index] = (SolidifyCorner){ | ||||
| .valid = true, | .valid = true, | ||||
| .edges = edges, | .edges = edges, | ||||
| .edges_len = (edges_len - (uint)last_split), | .edges_len = (edges_len - (uint)last_split), | ||||
| .open_face_edge = MOD_SOLIDIFY_EMPTY_TAG, | .open_poly_edge = MOD_SOLIDIFY_EMPTY_TAG, | ||||
| .is_orig_closed = g.is_orig_closed, | .is_orig_closed = g.is_orig_closed, | ||||
| .is_even_split = false, | .is_even_split = false, | ||||
| .split = add_index - prior_index + 1, | .split = add_index - prior_index + 1, | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| if (first_unique_end != -1 && prior_splits == splits) { | if (first_unique_end != -1 && prior_splits == splits) { | ||||
| has_singularities = true; | result->has_singularities = true; | ||||
| edge_groups[j + add_index].is_singularity = true; | corners[j + add_index].is_singularity = true; | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(doubles); | MEM_freeN(doubles); | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| orig_vert_groups_arr[i] = edge_groups; | result->corners_from_vert[i] = corners; | ||||
| /* Count new edges, loops, polys and add to link_edge_groups. */ | /* Count new edges, loops, polys and add to link_corners. */ | ||||
| { | { | ||||
| uint new_verts = 0; | uint new_verts = 0; | ||||
| bool contains_open_splits = false; | bool contains_open_splits = false; | ||||
| Context not available. | |||||
| uint last_added = 0; | uint last_added = 0; | ||||
| uint first_added = 0; | uint first_added = 0; | ||||
| bool first_set = false; | bool first_set = false; | ||||
| for (EdgeGroup *g = edge_groups; g->valid; g++) { | for (SolidifyCorner *g = corners; g->valid; g++) { | ||||
| NewEdgeRef **e = g->edges; | SolidifyEdge **e = g->edges; | ||||
| for (uint j = 0; j < g->edges_len; j++, e++) { | for (uint j = 0; j < g->edges_len; j++, e++) { | ||||
| const uint flip = (uint)(vm[orig_medge[(*e)->old_edge].v2] == i); | const uint flip = (uint)(vm[orig_medge[(*e)->orig_edge].v2] == i); | ||||
| BLI_assert(flip || vm[orig_medge[(*e)->old_edge].v1] == i); | BLI_assert(flip || vm[orig_medge[(*e)->orig_edge].v1] == i); | ||||
| (*e)->link_edge_groups[flip] = g; | (*e)->link_corners[flip] = g; | ||||
| } | } | ||||
| uint added = 0; | uint added = 0; | ||||
| if (do_shell || (do_rim && !g->is_orig_closed)) { | if (sctx->do_shell || (sctx->do_rim && !g->is_orig_closed)) { | ||||
| BLI_assert(g->new_vert == MOD_SOLIDIFY_EMPTY_TAG); | BLI_assert(g->new_vert == MOD_SOLIDIFY_EMPTY_TAG); | ||||
| g->new_vert = numNewVerts++; | g->new_vert = result->numVerts++; | ||||
| if (do_rim || (do_shell && g->split)) { | if (sctx->do_rim || (sctx->do_shell && g->split)) { | ||||
| new_verts++; | new_verts++; | ||||
| contains_splits += (g->split != 0); | contains_splits += (g->split != 0); | ||||
| contains_open_splits |= g->split && !g->is_orig_closed; | contains_open_splits |= g->split && !g->is_orig_closed; | ||||
| Context not available. | |||||
| last_added = added; | last_added = added; | ||||
| if (!(g + 1)->valid || g->topo_group != (g + 1)->topo_group) { | if (!(g + 1)->valid || g->topo_group != (g + 1)->topo_group) { | ||||
| if (new_verts > 2) { | if (new_verts > 2) { | ||||
| numNewPolys++; | result->numPolys++; | ||||
| numNewEdges += new_verts; | result->numEdges += new_verts; | ||||
| open_edges += (uint)(first_added < last_added); | open_edges += (uint)(first_added < last_added); | ||||
| open_edges -= (uint)(open_edges && !contains_open_splits); | open_edges -= (uint)(open_edges && !contains_open_splits); | ||||
| if (do_shell && do_rim) { | if (sctx->do_shell && sctx->do_rim) { | ||||
| numNewLoops += new_verts * 2; | result->numLoops += new_verts * 2; | ||||
| } | } | ||||
| else if (do_shell) { | else if (sctx->do_shell) { | ||||
| numNewLoops += new_verts * 2 - open_edges; | result->numLoops += new_verts * 2 - open_edges; | ||||
| } | } | ||||
| else { // do_rim | else { // do_rim | ||||
| numNewLoops += new_verts * 2 + open_edges - contains_splits; | result->numLoops += new_verts * 2 + open_edges - contains_splits; | ||||
| } | } | ||||
| } | } | ||||
| else if (new_verts == 2) { | else if (new_verts == 2) { | ||||
| numNewEdges++; | result->numEdges++; | ||||
| numNewLoops += 2u - (uint)(!(do_rim && do_shell) && contains_open_splits); | result->numLoops += 2u - (uint)(!(sctx->do_rim && sctx->do_shell) && contains_open_splits); | ||||
| } | } | ||||
| new_verts = 0; | new_verts = 0; | ||||
| contains_open_splits = false; | contains_open_splits = false; | ||||
| Context not available. | |||||
| /* Free vert_adj_edges memory. */ | /* Free vert_adj_edges memory. */ | ||||
| { | { | ||||
| uint i = 0; | uint i = 0; | ||||
| for (OldVertEdgeRef **p = vert_adj_edges; i < numVerts; i++, p++) { | for (VertEdgeLink **p = vert_adj_edges; i < numVerts; i++, p++) { | ||||
| if (*p) { | if (*p) { | ||||
| MEM_freeN((*p)->edges); | MEM_freeN((*p)->edges); | ||||
| MEM_freeN(*p); | MEM_freeN(*p); | ||||
| Context not available. | |||||
| } | } | ||||
| MEM_freeN(vert_adj_edges); | MEM_freeN(vert_adj_edges); | ||||
| } | } | ||||
| } | |||||
| /* TODO create_regions if fix_intersections. */ | |||||
| /* General use pointer for #EdgeGroup iteration. */ | static void solidify_set_new_vertex_coordinates(SolidifyContext *sctx) { | ||||
| EdgeGroup **gs_ptr; | SolidifyMesh *result = sctx->result; | ||||
| const SolidifyModifierData *smd = sctx->smd; | |||||
| const Mesh *mesh = sctx->mesh; | |||||
| float(*poly_nors)[3] = sctx->poly_nors; | |||||
| MVert *mv, *orig_mvert; | |||||
| MEdge *orig_medge; | |||||
| MLoop *ml, *orig_mloop; | |||||
| MPoly *mp, *orig_mpoly; | |||||
| const uint numVerts = (uint)mesh->totvert; | |||||
| const uint numPolys = (uint)mesh->totpoly; | |||||
| /* Calculate EdgeGroup vertex coordinates. */ | orig_mvert = mesh->mvert; | ||||
| orig_medge = mesh->medge; | |||||
| orig_mloop = mesh->mloop; | |||||
| orig_mpoly = mesh->mpoly; | |||||
| SolidifyCorner **gs_ptr; | |||||
| uint *vm = sctx->vm; | |||||
| float(*orig_mvert_co)[3] = sctx->orig_mvert_co; | |||||
| /* Calculate SolidifyCorner vertex coordinates. */ | |||||
| { | { | ||||
| float *face_weight = NULL; | float *poly_weight = NULL; | ||||
| if (do_flat_faces) { | if (sctx->do_flat_faces) { | ||||
| face_weight = MEM_malloc_arrayN(numPolys, sizeof(*face_weight), "face_weight in solidify"); | poly_weight = MEM_malloc_arrayN(numPolys, sizeof(*poly_weight), "poly_weight in solidify"); | ||||
| mp = orig_mpoly; | mp = orig_mpoly; | ||||
| for (uint i = 0; i < numPolys; i++, mp++) { | for (uint i = 0; i < numPolys; i++, mp++) { | ||||
| Context not available. | |||||
| int loopend = mp->loopstart + mp->totloop; | int loopend = mp->loopstart + mp->totloop; | ||||
| ml = orig_mloop + mp->loopstart; | ml = orig_mloop + mp->loopstart; | ||||
| for (int j = mp->loopstart; j < loopend; j++, ml++) { | for (int j = mp->loopstart; j < loopend; j++, ml++) { | ||||
| MDeformVert *dv = &dvert[ml->v]; | MDeformVert *dv = &sctx->dvert[ml->v]; | ||||
| if (defgrp_invert) { | if (sctx->defgrp_invert) { | ||||
| scalar_vgroup = min_ff(1.0f - BKE_defvert_find_weight(dv, defgrp_index), | scalar_vgroup = min_ff(1.0f - BKE_defvert_find_weight(dv, sctx->defgrp_index), | ||||
| scalar_vgroup); | scalar_vgroup); | ||||
| } | } | ||||
| else { | else { | ||||
| scalar_vgroup = min_ff(BKE_defvert_find_weight(dv, defgrp_index), scalar_vgroup); | scalar_vgroup = min_ff(BKE_defvert_find_weight(dv, sctx->defgrp_index), scalar_vgroup); | ||||
| } | } | ||||
| } | } | ||||
| face_weight[i] = scalar_vgroup; | poly_weight[i] = scalar_vgroup; | ||||
| } | } | ||||
| } | } | ||||
| mv = orig_mvert; | mv = orig_mvert; | ||||
| gs_ptr = orig_vert_groups_arr; | gs_ptr = result->corners_from_vert; | ||||
| for (uint i = 0; i < numVerts; i++, mv++, gs_ptr++) { | for (uint i = 0; i < numVerts; i++, mv++, gs_ptr++) { | ||||
| if (*gs_ptr) { | if (*gs_ptr) { | ||||
| EdgeGroup *g = *gs_ptr; | SolidifyCorner *g = *gs_ptr; | ||||
| for (uint j = 0; g->valid; j++, g++) { | for (uint j = 0; g->valid; j++, g++) { | ||||
| if (!g->is_singularity) { | if (!g->is_singularity) { | ||||
| float *nor = g->no; | float *nor = g->no; | ||||
| Context not available. | |||||
| (g->is_orig_closed || g->split)); | (g->is_orig_closed || g->split)); | ||||
| /* Constraints Method. */ | /* Constraints Method. */ | ||||
| if (smd->nonmanifold_offset_mode == MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS) { | if (smd->nonmanifold_offset_mode == MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS) { | ||||
| NewEdgeRef *first_edge = NULL; | SolidifyEdge *first_edge = NULL; | ||||
| NewEdgeRef **edge_ptr = g->edges; | SolidifyEdge **edge_ptr = g->edges; | ||||
| /* Contains normal and offset [nx, ny, nz, ofs]. */ | /* Contains normal and offset [nx, ny, nz, ofs]. */ | ||||
| float(*normals_queue)[4] = MEM_malloc_arrayN( | float(*normals_queue)[4] = MEM_malloc_arrayN( | ||||
| g->edges_len + 1, sizeof(*normals_queue), "normals_queue in solidify"); | g->edges_len + 1, sizeof(*normals_queue), "normals_queue in solidify"); | ||||
| uint queue_index = 0; | uint queue_index = 0; | ||||
| float face_nors[3][3]; | float plane_nors[3][3]; | ||||
| float nor_ofs[3]; | float nor_ofs[3]; | ||||
| const bool cycle = (g->is_orig_closed && !g->split) || g->is_even_split; | const bool cycle = (g->is_orig_closed && !g->split) || g->is_even_split; | ||||
| for (uint k = 0; k < g->edges_len; k++, edge_ptr++) { | for (uint k = 0; k < g->edges_len; k++, edge_ptr++) { | ||||
| if (!(k & 1) || (!cycle && k == g->edges_len - 1)) { | if (!(k & 1) || (!cycle && k == g->edges_len - 1)) { | ||||
| NewEdgeRef *edge = *edge_ptr; | SolidifyEdge *edge = *edge_ptr; | ||||
| for (uint l = 0; l < 2; l++) { | for (uint l = 0; l < 2; l++) { | ||||
| NewFaceRef *face = edge->faces[l]; | SolidifyPoly *poly = edge->polys[l]; | ||||
| if (face && (first_edge == NULL || | if (poly && (first_edge == NULL || | ||||
| (first_edge->faces[0] != face && first_edge->faces[1] != face))) { | (first_edge->polys[0] != poly && first_edge->polys[1] != poly))) { | ||||
| float ofs = face->reversed ? ofs_back_clamped : ofs_front_clamped; | float ofs = poly->reversed ? sctx->ofs_back_clamped : sctx->ofs_front_clamped; | ||||
| /* Use face_weight here to make faces thinner. */ | /* Use poly_weight here to make polys thinner. */ | ||||
| if (do_flat_faces) { | if (sctx->do_flat_faces) { | ||||
| ofs *= face_weight[face->index]; | ofs *= poly_weight[poly->orig_poly_index]; | ||||
| } | } | ||||
| if (!null_faces[face->index]) { | if (!sctx->null_polys[poly->orig_poly_index]) { | ||||
| /* And normal to the queue. */ | /* And normal to the queue. */ | ||||
| mul_v3_v3fl(normals_queue[queue_index], | mul_v3_v3fl(normals_queue[queue_index], | ||||
| poly_nors[face->index], | poly_nors[poly->orig_poly_index], | ||||
| face->reversed ? -1 : 1); | poly->reversed ? -1 : 1); | ||||
| normals_queue[queue_index++][3] = ofs; | normals_queue[queue_index++][3] = ofs; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Just use this approximate normal of the null face if there is no other | /* Just use this approximate normal of the null poly if there is no other | ||||
| * normal to use. */ | * normal to use. */ | ||||
| mul_v3_v3fl(face_nors[0], poly_nors[face->index], face->reversed ? -1 : 1); | mul_v3_v3fl(plane_nors[0], | ||||
| poly_nors[poly->orig_poly_index], | |||||
| poly->reversed ? -1 : 1); | |||||
| nor_ofs[0] = ofs; | nor_ofs[0] = ofs; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| uint face_nors_len = 0; | uint plane_nors_len = 0; | ||||
| const float stop_explosion = 0.999f - fabsf(smd->offset_fac) * 0.05f; | const float stop_explosion = 0.999f - fabsf(smd->offset_fac) * 0.05f; | ||||
| while (queue_index > 0) { | while (queue_index > 0) { | ||||
| if (face_nors_len == 0) { | if (plane_nors_len == 0) { | ||||
| if (queue_index <= 2) { | if (queue_index <= 2) { | ||||
| for (uint k = 0; k < queue_index; k++) { | for (uint k = 0; k < queue_index; k++) { | ||||
| copy_v3_v3(face_nors[k], normals_queue[k]); | copy_v3_v3(plane_nors[k], normals_queue[k]); | ||||
| nor_ofs[k] = normals_queue[k][3]; | nor_ofs[k] = normals_queue[k][3]; | ||||
| } | } | ||||
| face_nors_len = queue_index; | plane_nors_len = queue_index; | ||||
| queue_index = 0; | queue_index = 0; | ||||
| } | } | ||||
| else { | else { | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| copy_v3_v3(face_nors[0], normals_queue[min_n0]); | copy_v3_v3(plane_nors[0], normals_queue[min_n0]); | ||||
| copy_v3_v3(face_nors[1], normals_queue[min_n1]); | copy_v3_v3(plane_nors[1], normals_queue[min_n1]); | ||||
| nor_ofs[0] = normals_queue[min_n0][3]; | nor_ofs[0] = normals_queue[min_n0][3]; | ||||
| nor_ofs[1] = normals_queue[min_n1][3]; | nor_ofs[1] = normals_queue[min_n1][3]; | ||||
| face_nors_len = 2; | plane_nors_len = 2; | ||||
| queue_index--; | queue_index--; | ||||
| memmove(normals_queue + min_n0, | memmove(normals_queue + min_n0, | ||||
| normals_queue + min_n0 + 1, | normals_queue + min_n0 + 1, | ||||
| Context not available. | |||||
| float max_p = -1; | float max_p = -1; | ||||
| for (uint k = 0; k < queue_index; k++) { | for (uint k = 0; k < queue_index; k++) { | ||||
| max_p = -1; | max_p = -1; | ||||
| for (uint m = 0; m < face_nors_len; m++) { | for (uint m = 0; m < plane_nors_len; m++) { | ||||
| float p = dot_v3v3(face_nors[m], normals_queue[k]); | float p = dot_v3v3(plane_nors[m], normals_queue[k]); | ||||
| if (p > max_p + FLT_EPSILON) { | if (p > max_p + FLT_EPSILON) { | ||||
| max_p = p; | max_p = p; | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| if (min_p < 0.8) { | if (min_p < 0.8) { | ||||
| copy_v3_v3(face_nors[2], normals_queue[min_n1]); | copy_v3_v3(plane_nors[2], normals_queue[min_n1]); | ||||
| nor_ofs[2] = normals_queue[min_n1][3]; | nor_ofs[2] = normals_queue[min_n1][3]; | ||||
| face_nors_len++; | plane_nors_len++; | ||||
| queue_index--; | queue_index--; | ||||
| memmove(normals_queue + min_n1, | memmove(normals_queue + min_n1, | ||||
| normals_queue + min_n1 + 1, | normals_queue + min_n1 + 1, | ||||
| Context not available. | |||||
| uint best_group = 0; | uint best_group = 0; | ||||
| float best_p = -1.0f; | float best_p = -1.0f; | ||||
| for (uint k = 0; k < queue_index; k++) { | for (uint k = 0; k < queue_index; k++) { | ||||
| for (uint m = 0; m < face_nors_len; m++) { | for (uint m = 0; m < plane_nors_len; m++) { | ||||
| float p = dot_v3v3(face_nors[m], normals_queue[k]); | float p = dot_v3v3(plane_nors[m], normals_queue[k]); | ||||
| if (p > best_p + FLT_EPSILON) { | if (p > best_p + FLT_EPSILON) { | ||||
| best_p = p; | best_p = p; | ||||
| best = m; | best = m; | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| add_v3_v3(face_nors[best], normals_queue[best_group]); | add_v3_v3(plane_nors[best], normals_queue[best_group]); | ||||
| normalize_v3(face_nors[best]); | normalize_v3(plane_nors[best]); | ||||
| nor_ofs[best] = (nor_ofs[best] + normals_queue[best_group][3]) * 0.5f; | nor_ofs[best] = (nor_ofs[best] + normals_queue[best_group][3]) * 0.5f; | ||||
| queue_index--; | queue_index--; | ||||
| memmove(normals_queue + best_group, | memmove(normals_queue + best_group, | ||||
| Context not available. | |||||
| MEM_freeN(normals_queue); | MEM_freeN(normals_queue); | ||||
| /* When up to 3 constraint normals are found. */ | /* When up to 3 constraint normals are found. */ | ||||
| if (ELEM(face_nors_len, 2, 3)) { | if (ELEM(plane_nors_len, 2, 3)) { | ||||
| const float q = dot_v3v3(face_nors[0], face_nors[1]); | const float q = dot_v3v3(plane_nors[0], plane_nors[1]); | ||||
| float d = 1.0f - q * q; | float d = 1.0f - q * q; | ||||
| cross_v3_v3v3(move_nor, face_nors[0], face_nors[1]); | cross_v3_v3v3(move_nor, plane_nors[0], plane_nors[1]); | ||||
| if (d > FLT_EPSILON * 10 && q < stop_explosion) { | if (d > FLT_EPSILON * 10 && q < stop_explosion) { | ||||
| d = 1.0f / d; | d = 1.0f / d; | ||||
| mul_v3_fl(face_nors[0], (nor_ofs[0] - nor_ofs[1] * q) * d); | mul_v3_fl(plane_nors[0], (nor_ofs[0] - nor_ofs[1] * q) * d); | ||||
| mul_v3_fl(face_nors[1], (nor_ofs[1] - nor_ofs[0] * q) * d); | mul_v3_fl(plane_nors[1], (nor_ofs[1] - nor_ofs[0] * q) * d); | ||||
| } | } | ||||
| else { | else { | ||||
| d = 1.0f / (fabsf(q) + 1.0f); | d = 1.0f / (fabsf(q) + 1.0f); | ||||
| mul_v3_fl(face_nors[0], nor_ofs[0] * d); | mul_v3_fl(plane_nors[0], nor_ofs[0] * d); | ||||
| mul_v3_fl(face_nors[1], nor_ofs[1] * d); | mul_v3_fl(plane_nors[1], nor_ofs[1] * d); | ||||
| } | } | ||||
| add_v3_v3v3(nor, face_nors[0], face_nors[1]); | add_v3_v3v3(nor, plane_nors[0], plane_nors[1]); | ||||
| if (face_nors_len == 3) { | if (plane_nors_len == 3) { | ||||
| float *free_nor = move_nor; | float *free_nor = move_nor; | ||||
| mul_v3_fl(face_nors[2], nor_ofs[2]); | mul_v3_fl(plane_nors[2], nor_ofs[2]); | ||||
| d = dot_v3v3(face_nors[2], free_nor); | d = dot_v3v3(plane_nors[2], free_nor); | ||||
| if (LIKELY(fabsf(d) > FLT_EPSILON)) { | if (LIKELY(fabsf(d) > FLT_EPSILON)) { | ||||
| sub_v3_v3v3(face_nors[0], nor, face_nors[2]); /* Override face_nor[0]. */ | sub_v3_v3v3(plane_nors[0], nor, plane_nors[2]); /* Override poly_nor[0]. */ | ||||
| mul_v3_fl(free_nor, dot_v3v3(face_nors[2], face_nors[0]) / d); | mul_v3_fl(free_nor, dot_v3v3(plane_nors[2], plane_nors[0]) / d); | ||||
| sub_v3_v3(nor, free_nor); | sub_v3_v3(nor, free_nor); | ||||
| } | } | ||||
| disable_boundary_fix = true; | disable_boundary_fix = true; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_assert(face_nors_len < 2); | BLI_assert(plane_nors_len < 2); | ||||
| mul_v3_v3fl(nor, face_nors[0], nor_ofs[0]); | mul_v3_v3fl(nor, plane_nors[0], nor_ofs[0]); | ||||
| disable_boundary_fix = true; | disable_boundary_fix = true; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| else { | else { | ||||
| float total_angle = 0; | float total_angle = 0; | ||||
| float total_angle_back = 0; | float total_angle_back = 0; | ||||
| NewEdgeRef *first_edge = NULL; | SolidifyEdge *first_edge = NULL; | ||||
| NewEdgeRef **edge_ptr = g->edges; | SolidifyEdge **edge_ptr = g->edges; | ||||
| float face_nor[3]; | float poly_nor[3]; | ||||
| float nor_back[3] = {0, 0, 0}; | float nor_back[3] = {0, 0, 0}; | ||||
| bool has_back = false; | bool has_back = false; | ||||
| bool has_front = false; | bool has_front = false; | ||||
| bool cycle = (g->is_orig_closed && !g->split) || g->is_even_split; | bool cycle = (g->is_orig_closed && !g->split) || g->is_even_split; | ||||
| for (uint k = 0; k < g->edges_len; k++, edge_ptr++) { | for (uint k = 0; k < g->edges_len; k++, edge_ptr++) { | ||||
| if (!(k & 1) || (!cycle && k == g->edges_len - 1)) { | if (!(k & 1) || (!cycle && k == g->edges_len - 1)) { | ||||
| NewEdgeRef *edge = *edge_ptr; | SolidifyEdge *edge = *edge_ptr; | ||||
| for (uint l = 0; l < 2; l++) { | for (uint l = 0; l < 2; l++) { | ||||
| NewFaceRef *face = edge->faces[l]; | SolidifyPoly *poly = edge->polys[l]; | ||||
| if (face && (first_edge == NULL || | if (poly && (first_edge == NULL || | ||||
| (first_edge->faces[0] != face && first_edge->faces[1] != face))) { | (first_edge->polys[0] != poly && first_edge->polys[1] != poly))) { | ||||
| float angle = 1.0f; | float angle = 1.0f; | ||||
| float ofs = face->reversed ? -ofs_back_clamped : ofs_front_clamped; | float ofs = poly->reversed ? -sctx->ofs_back_clamped : sctx->ofs_front_clamped; | ||||
| /* Use face_weight here to make faces thinner. */ | /* Use poly_weight here to make polys thinner. */ | ||||
| if (do_flat_faces) { | if (sctx->do_flat_faces) { | ||||
| ofs *= face_weight[face->index]; | ofs *= poly_weight[poly->orig_poly_index]; | ||||
| } | } | ||||
| if (smd->nonmanifold_offset_mode == | if (smd->nonmanifold_offset_mode == | ||||
| MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN) { | MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN) { | ||||
| MLoop *ml_next = orig_mloop + face->face->loopstart; | MLoop *ml_next = orig_mloop + poly->poly->loopstart; | ||||
| ml = ml_next + (face->face->totloop - 1); | ml = ml_next + (poly->poly->totloop - 1); | ||||
| MLoop *ml_prev = ml - 1; | MLoop *ml_prev = ml - 1; | ||||
| for (int m = 0; m < face->face->totloop && vm[ml->v] != i; | for (int m = 0; m < poly->poly->totloop && vm[ml->v] != i; | ||||
| m++, ml_next++) { | m++, ml_next++) { | ||||
| ml_prev = ml; | ml_prev = ml; | ||||
| ml = ml_next; | ml = ml_next; | ||||
| Context not available. | |||||
| angle = angle_v3v3v3(orig_mvert_co[vm[ml_prev->v]], | angle = angle_v3v3v3(orig_mvert_co[vm[ml_prev->v]], | ||||
| orig_mvert_co[i], | orig_mvert_co[i], | ||||
| orig_mvert_co[vm[ml_next->v]]); | orig_mvert_co[vm[ml_next->v]]); | ||||
| if (face->reversed) { | if (poly->reversed) { | ||||
| total_angle_back += angle * ofs * ofs; | total_angle_back += angle * ofs * ofs; | ||||
| } | } | ||||
| else { | else { | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if (face->reversed) { | if (poly->reversed) { | ||||
| total_angle_back++; | total_angle_back++; | ||||
| } | } | ||||
| else { | else { | ||||
| total_angle++; | total_angle++; | ||||
| } | } | ||||
| } | } | ||||
| mul_v3_v3fl(face_nor, poly_nors[face->index], angle * ofs); | mul_v3_v3fl(poly_nor, poly_nors[poly->orig_poly_index], angle * ofs); | ||||
| if (face->reversed) { | if (poly->reversed) { | ||||
| add_v3_v3(nor_back, face_nor); | add_v3_v3(nor_back, poly_nor); | ||||
| has_back = true; | has_back = true; | ||||
| } | } | ||||
| else { | else { | ||||
| add_v3_v3(nor, face_nor); | add_v3_v3(nor, poly_nor); | ||||
| has_front = true; | has_front = true; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| float tmp[3]; | float tmp[3]; | ||||
| uint k; | uint k; | ||||
| for (k = 1; k + 1 < g->edges_len; k++, edge_ptr++) { | for (k = 1; k + 1 < g->edges_len; k++, edge_ptr++) { | ||||
| MEdge *e = orig_medge + (*edge_ptr)->old_edge; | MEdge *e = orig_medge + (*edge_ptr)->orig_edge; | ||||
| sub_v3_v3v3( | sub_v3_v3v3( | ||||
| tmp, orig_mvert_co[vm[e->v1] == i ? e->v2 : e->v1], orig_mvert_co[i]); | tmp, orig_mvert_co[vm[e->v1] == i ? e->v2 : e->v1], orig_mvert_co[i]); | ||||
| add_v3_v3(move_nor, tmp); | add_v3_v3(move_nor, tmp); | ||||
| Context not available. | |||||
| if (!disable_boundary_fix) { | if (!disable_boundary_fix) { | ||||
| /* Constraint normal, nor * constr_nor == 0 after this fix. */ | /* Constraint normal, nor * constr_nor == 0 after this fix. */ | ||||
| float constr_nor[3]; | float constr_nor[3]; | ||||
| MEdge *e0_edge = orig_medge + g->edges[0]->old_edge; | MEdge *e0_edge = orig_medge + g->edges[0]->orig_edge; | ||||
| MEdge *e1_edge = orig_medge + g->edges[g->edges_len - 1]->old_edge; | MEdge *e1_edge = orig_medge + g->edges[g->edges_len - 1]->orig_edge; | ||||
| float e0[3]; | float e0[3]; | ||||
| float e1[3]; | float e1[3]; | ||||
| sub_v3_v3v3(e0, | sub_v3_v3v3(e0, | ||||
| Context not available. | |||||
| else { | else { | ||||
| float f0[3]; | float f0[3]; | ||||
| float f1[3]; | float f1[3]; | ||||
| if (g->edges[0]->faces[0]->reversed) { | if (g->edges[0]->polys[0]->reversed) { | ||||
| negate_v3_v3(f0, poly_nors[g->edges[0]->faces[0]->index]); | negate_v3_v3(f0, poly_nors[g->edges[0]->polys[0]->orig_poly_index]); | ||||
| } | } | ||||
| else { | else { | ||||
| copy_v3_v3(f0, poly_nors[g->edges[0]->faces[0]->index]); | copy_v3_v3(f0, poly_nors[g->edges[0]->polys[0]->orig_poly_index]); | ||||
| } | } | ||||
| if (g->edges[g->edges_len - 1]->faces[0]->reversed) { | if (g->edges[g->edges_len - 1]->polys[0]->reversed) { | ||||
| negate_v3_v3(f1, poly_nors[g->edges[g->edges_len - 1]->faces[0]->index]); | negate_v3_v3(f1, | ||||
| poly_nors[g->edges[g->edges_len - 1]->polys[0]->orig_poly_index]); | |||||
| } | } | ||||
| else { | else { | ||||
| copy_v3_v3(f1, poly_nors[g->edges[g->edges_len - 1]->faces[0]->index]); | copy_v3_v3(f1, poly_nors[g->edges[g->edges_len - 1]->polys[0]->orig_poly_index]); | ||||
| } | } | ||||
| float n0[3]; | float n0[3]; | ||||
| float n1[3]; | float n1[3]; | ||||
| Context not available. | |||||
| } | } | ||||
| float scalar_vgroup = 1; | float scalar_vgroup = 1; | ||||
| /* Use vertex group. */ | /* Use vertex group. */ | ||||
| if (dvert && !do_flat_faces) { | if (sctx->dvert && !sctx->do_flat_faces) { | ||||
| MDeformVert *dv = &dvert[i]; | MDeformVert *dv = &sctx->dvert[i]; | ||||
| if (defgrp_invert) { | if (sctx->defgrp_invert) { | ||||
| scalar_vgroup = 1.0f - BKE_defvert_find_weight(dv, defgrp_index); | scalar_vgroup = 1.0f - BKE_defvert_find_weight(dv, sctx->defgrp_index); | ||||
| } | } | ||||
| else { | else { | ||||
| scalar_vgroup = BKE_defvert_find_weight(dv, defgrp_index); | scalar_vgroup = BKE_defvert_find_weight(dv, sctx->defgrp_index); | ||||
| } | } | ||||
| scalar_vgroup = offset_fac_vg + (scalar_vgroup * offset_fac_vg_inv); | scalar_vgroup = sctx->offset_fac_vg + (scalar_vgroup * sctx->offset_fac_vg_inv); | ||||
| } | } | ||||
| /* Do clamping. */ | /* Do clamping. */ | ||||
| if (do_clamp) { | if (sctx->do_clamp) { | ||||
| if (do_angle_clamp) { | if (sctx->do_angle_clamp) { | ||||
| if (g->edges_len > 2) { | if (g->edges_len > 2) { | ||||
| float min_length = 0; | float min_length = 0; | ||||
| float angle = 0.5f * M_PI; | float angle = 0.5f * M_PI; | ||||
| uint k = 0; | uint k = 0; | ||||
| for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) { | for (SolidifyEdge **p = g->edges; k < g->edges_len; k++, p++) { | ||||
| float length = orig_edge_lengths[(*p)->old_edge]; | float length = sctx->orig_edge_lengths[(*p)->orig_edge]; | ||||
| float e_ang = (*p)->angle; | float e_ang = (*p)->angle; | ||||
| if (e_ang > angle) { | if (e_ang > angle) { | ||||
| angle = e_ang; | angle = e_ang; | ||||
| Context not available. | |||||
| float cos_ang = cosf(angle * 0.5f); | float cos_ang = cosf(angle * 0.5f); | ||||
| if (cos_ang > 0) { | if (cos_ang > 0) { | ||||
| float max_off = min_length * 0.5f / cos_ang; | float max_off = min_length * 0.5f / cos_ang; | ||||
| if (max_off < offset * 0.5f) { | if (max_off < sctx->offset * 0.5f) { | ||||
| scalar_vgroup *= max_off / offset * 2; | scalar_vgroup *= max_off / sctx->offset * 2; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| else { | else { | ||||
| float min_length = 0; | float min_length = 0; | ||||
| uint k = 0; | uint k = 0; | ||||
| for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) { | for (SolidifyEdge **p = g->edges; k < g->edges_len; k++, p++) { | ||||
| float length = orig_edge_lengths[(*p)->old_edge]; | float length = sctx->orig_edge_lengths[(*p)->orig_edge]; | ||||
| if (length < min_length || k == 0) { | if (length < min_length || k == 0) { | ||||
| min_length = length; | min_length = length; | ||||
| } | } | ||||
| } | } | ||||
| if (min_length < offset) { | if (min_length < sctx->offset) { | ||||
| scalar_vgroup *= min_length / offset; | scalar_vgroup *= min_length / sctx->offset; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| if (do_flat_faces) { | if (sctx->do_flat_faces) { | ||||
| MEM_freeN(face_weight); | MEM_freeN(poly_weight); | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(orig_mvert_co); | MEM_freeN(sctx->orig_mvert_co); | ||||
| if (null_faces) { | if (sctx->null_polys) { | ||||
| MEM_freeN(null_faces); | MEM_freeN(sctx->null_polys); | ||||
| } | } | ||||
| } | |||||
| /* TODO create vertdata for intersection fixes (intersection fixing per topology region). */ | |||||
| /* Correction for adjacent one sided groups around a vert to | static void solidify_create_final_mesh(SolidifyContext *sctx) { | ||||
| * prevent edge duplicates and null polys. */ | SolidifyMesh *result = sctx->result; | ||||
| uint(*singularity_edges)[2] = NULL; | const SolidifyModifierData *smd = sctx->smd; | ||||
| uint totsingularity = 0; | const Mesh *mesh = sctx->mesh; | ||||
| if (has_singularities) { | |||||
| has_singularities = false; | MVert *mv, *mvert, *orig_mvert; | ||||
| uint i = 0; | MEdge *ed, *medge, *orig_medge; | ||||
| uint singularity_edges_len = 1; | MLoop *ml, *mloop, *orig_mloop; | ||||
| singularity_edges = MEM_malloc_arrayN( | MPoly *mpoly, *orig_mpoly; | ||||
| singularity_edges_len, sizeof(*singularity_edges), "singularity_edges in solidify"); | const uint numVerts = (uint)mesh->totvert; | ||||
| for (NewEdgeRef ***new_edges = orig_edge_data_arr; i < numEdges; i++, new_edges++) { | const uint numEdges = (uint)mesh->totedge; | ||||
| if (*new_edges && (do_shell || edge_adj_faces_len[i] == 1) && (**new_edges)->old_edge == i) { | const uint numPolys = (uint)mesh->totpoly; | ||||
| for (NewEdgeRef **l = *new_edges; *l; l++) { | |||||
| if ((*l)->link_edge_groups[0]->is_singularity && | orig_mvert = mesh->mvert; | ||||
| (*l)->link_edge_groups[1]->is_singularity) { | orig_medge = mesh->medge; | ||||
| const uint v1 = (*l)->link_edge_groups[0]->new_vert; | orig_mloop = mesh->mloop; | ||||
| const uint v2 = (*l)->link_edge_groups[1]->new_vert; | orig_mpoly = mesh->mpoly; | ||||
| bool exists_already = false; | |||||
| uint j = 0; | mpoly = result->mesh->mpoly; | ||||
| for (uint(*p)[2] = singularity_edges; j < totsingularity; p++, j++) { | mloop = result->mesh->mloop; | ||||
| if (((*p)[0] == v1 && (*p)[1] == v2) || ((*p)[0] == v2 && (*p)[1] == v1)) { | medge = result->mesh->medge; | ||||
| exists_already = true; | mvert = result->mesh->mvert; | ||||
| break; | |||||
| } | |||||
| } | |||||
| if (!exists_already) { | |||||
| has_singularities = true; | |||||
| if (singularity_edges_len <= totsingularity) { | |||||
| singularity_edges_len = totsingularity + 1; | |||||
| singularity_edges = MEM_reallocN_id(singularity_edges, | |||||
| singularity_edges_len * | |||||
| sizeof(*singularity_edges), | |||||
| "singularity_edges in solidify"); | |||||
| } | |||||
| singularity_edges[totsingularity][0] = v1; | |||||
| singularity_edges[totsingularity][1] = v2; | |||||
| totsingularity++; | |||||
| if (edge_adj_faces_len[i] == 1 && do_rim) { | |||||
| numNewLoops -= 2; | |||||
| numNewPolys--; | |||||
| } | |||||
| } | |||||
| else { | |||||
| numNewEdges--; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /* Create Mesh *result with proper capacity. */ | uint *vm = sctx->vm; | ||||
| result = BKE_mesh_new_nomain_from_template( | |||||
| mesh, (int)(numNewVerts), (int)(numNewEdges), 0, (int)(numNewLoops), (int)(numNewPolys)); | |||||
| mpoly = result->mpoly; | uint edge_index = 0; | ||||
| mloop = result->mloop; | uint loop_index = 0; | ||||
| medge = result->medge; | uint poly_index = 0; | ||||
| mvert = result->mvert; | |||||
| int *origindex_edge = CustomData_get_layer(&result->edata, CD_ORIGINDEX); | int *origindex_edge = CustomData_get_layer(&result->mesh->edata, CD_ORIGINDEX); | ||||
| int *origindex_poly = CustomData_get_layer(&result->pdata, CD_ORIGINDEX); | int *origindex_poly = CustomData_get_layer(&result->mesh->pdata, CD_ORIGINDEX); | ||||
| if (bevel_convex != 0.0f) { | if (sctx->bevel_convex != 0.0f) { | ||||
| /* make sure bweight is enabled */ | /* make sure bweight is enabled */ | ||||
| result->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT; | result->mesh->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT; | ||||
| } | } | ||||
| /* Checks that result has dvert data. */ | /* Checks that result->mesh has dvert data. */ | ||||
| if (shell_defgrp_index != -1 || rim_defgrp_index != -1) { | if (sctx->shell_defgrp_index != -1 || sctx->rim_defgrp_index != -1) { | ||||
| dvert = CustomData_duplicate_referenced_layer(&result->vdata, CD_MDEFORMVERT, result->totvert); | sctx->dvert = CustomData_duplicate_referenced_layer( | ||||
| &result->mesh->vdata, CD_MDEFORMVERT, result->mesh->totvert); | |||||
| /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */ | /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */ | ||||
| if (dvert == NULL) { | if (sctx->dvert == NULL) { | ||||
| /* Add a valid data layer! */ | /* Add a valid data layer! */ | ||||
| dvert = CustomData_add_layer( | sctx->dvert = CustomData_add_layer( | ||||
| &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, result->totvert); | &result->mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, result->mesh->totvert); | ||||
| } | } | ||||
| result->dvert = dvert; | result->mesh->dvert = sctx->dvert; | ||||
| } | } | ||||
| /* Make_new_verts. */ | /* Make_new_verts. */ | ||||
| { | { | ||||
| gs_ptr = orig_vert_groups_arr; | SolidifyCorner **gs_ptr = result->corners_from_vert; | ||||
| for (uint i = 0; i < numVerts; i++, gs_ptr++) { | for (uint i = 0; i < numVerts; i++, gs_ptr++) { | ||||
| EdgeGroup *gs = *gs_ptr; | SolidifyCorner *gs = *gs_ptr; | ||||
| if (gs) { | if (gs) { | ||||
| EdgeGroup *g = gs; | SolidifyCorner *g = gs; | ||||
| for (uint j = 0; g->valid; j++, g++) { | for (uint j = 0; g->valid; j++, g++) { | ||||
| if (g->new_vert != MOD_SOLIDIFY_EMPTY_TAG) { | if (g->new_vert != MOD_SOLIDIFY_EMPTY_TAG) { | ||||
| CustomData_copy_data(&mesh->vdata, &result->vdata, (int)i, (int)g->new_vert, 1); | CustomData_copy_data(&mesh->vdata, &result->mesh->vdata, (int)i, (int)g->new_vert, 1); | ||||
| copy_v3_v3(mvert[g->new_vert].co, g->co); | copy_v3_v3(mvert[g->new_vert].co, g->co); | ||||
| mvert[g->new_vert].flag = orig_mvert[i].flag; | mvert[g->new_vert].flag = orig_mvert[i].flag; | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; | result->mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; | ||||
| /* Make edges. */ | /* Make edges. */ | ||||
| { | { | ||||
| uint i = 0; | uint i = 0; | ||||
| edge_index += totsingularity; | edge_index += sctx->totsingularity; | ||||
| for (NewEdgeRef ***new_edges = orig_edge_data_arr; i < numEdges; i++, new_edges++) { | for (SolidifyEdge ***new_edges = result->edges; i < numEdges; i++, new_edges++) { | ||||
| if (*new_edges && (do_shell || edge_adj_faces_len[i] == 1) && (**new_edges)->old_edge == i) { | if (*new_edges && (sctx->do_shell || sctx->edge_adj_polys_len[i] == 1) && | ||||
| for (NewEdgeRef **l = *new_edges; *l; l++) { | (**new_edges)->orig_edge == i) { | ||||
| for (SolidifyEdge **l = *new_edges; *l; l++) { | |||||
| if ((*l)->new_edge != MOD_SOLIDIFY_EMPTY_TAG) { | if ((*l)->new_edge != MOD_SOLIDIFY_EMPTY_TAG) { | ||||
| const uint v1 = (*l)->link_edge_groups[0]->new_vert; | const uint v1 = (*l)->link_corners[0]->new_vert; | ||||
| const uint v2 = (*l)->link_edge_groups[1]->new_vert; | const uint v2 = (*l)->link_corners[1]->new_vert; | ||||
| uint insert = edge_index; | uint insert = edge_index; | ||||
| if (has_singularities && ((*l)->link_edge_groups[0]->is_singularity && | if (result->has_singularities && | ||||
| (*l)->link_edge_groups[1]->is_singularity)) { | ((*l)->link_corners[0]->is_singularity && (*l)->link_corners[1]->is_singularity)) { | ||||
| uint j = 0; | uint j = 0; | ||||
| for (uint(*p)[2] = singularity_edges; j < totsingularity; p++, j++) { | for (uint(*p)[2] = sctx->singularity_edges; j < sctx->totsingularity; p++, j++) { | ||||
| if (((*p)[0] == v1 && (*p)[1] == v2) || ((*p)[0] == v2 && (*p)[1] == v1)) { | if (((*p)[0] == v1 && (*p)[1] == v2) || ((*p)[0] == v2 && (*p)[1] == v1)) { | ||||
| insert = j; | insert = j; | ||||
| break; | break; | ||||
| Context not available. | |||||
| else { | else { | ||||
| edge_index++; | edge_index++; | ||||
| } | } | ||||
| CustomData_copy_data(&mesh->edata, &result->edata, (int)i, (int)insert, 1); | CustomData_copy_data(&mesh->edata, &result->mesh->edata, (int)i, (int)insert, 1); | ||||
| BLI_assert(v1 != MOD_SOLIDIFY_EMPTY_TAG); | BLI_assert(v1 != MOD_SOLIDIFY_EMPTY_TAG); | ||||
| BLI_assert(v2 != MOD_SOLIDIFY_EMPTY_TAG); | BLI_assert(v2 != MOD_SOLIDIFY_EMPTY_TAG); | ||||
| medge[insert].v1 = v1; | medge[insert].v1 = v1; | ||||
| medge[insert].v2 = v2; | medge[insert].v2 = v2; | ||||
| medge[insert].flag = orig_medge[(*l)->old_edge].flag | ME_EDGEDRAW | ME_EDGERENDER; | medge[insert].flag = orig_medge[(*l)->orig_edge].flag | ME_EDGEDRAW | ME_EDGERENDER; | ||||
| medge[insert].crease = orig_medge[(*l)->old_edge].crease; | medge[insert].crease = orig_medge[(*l)->orig_edge].crease; | ||||
| medge[insert].bweight = orig_medge[(*l)->old_edge].bweight; | medge[insert].bweight = orig_medge[(*l)->orig_edge].bweight; | ||||
| if (bevel_convex != 0.0f && (*l)->faces[1] != NULL) { | if (sctx->bevel_convex != 0.0f && (*l)->polys[1] != NULL) { | ||||
| medge[insert].bweight = (char)clamp_i( | medge[insert].bweight = (char)clamp_i( | ||||
| (int)medge[insert].bweight + (int)(((*l)->angle > M_PI + FLT_EPSILON ? | (int)medge[insert].bweight + (int)(((*l)->angle > M_PI + FLT_EPSILON ? | ||||
| clamp_f(bevel_convex, 0.0f, 1.0f) : | clamp_f(sctx->bevel_convex, 0.0f, 1.0f) : | ||||
| ((*l)->angle < M_PI - FLT_EPSILON ? | ((*l)->angle < M_PI - FLT_EPSILON ? | ||||
| clamp_f(bevel_convex, -1.0f, 0.0f) : | clamp_f(sctx->bevel_convex, -1.0f, 0.0f) : | ||||
| 0)) * | 0)) * | ||||
| 255), | 255), | ||||
| 0, | 0, | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (singularity_edges) { | if (sctx->singularity_edges) { | ||||
| MEM_freeN(singularity_edges); | MEM_freeN(sctx->singularity_edges); | ||||
| } | } | ||||
| /* DEBUG CODE FOR BUG-FIXING (can not be removed because every bug-fix needs this badly!). */ | /* DEBUG CODE FOR BUG-FIXING (can not be removed because every bug-fix needs this badly!). */ | ||||
| #if 0 | #if 0 | ||||
| { | { | ||||
| /* this code will output the content of orig_vert_groups_arr. | /* this code will output the content of result->corners_from_vert. | ||||
| * in orig_vert_groups_arr these conditions must be met for every vertex: | * in result->corners_from_vert these conditions must be met for every vertex: | ||||
| * - new_edge value should have no duplicates | * - new_edge value should have no duplicates | ||||
| * - every old_edge value should appear twice | * - every orig_edge value should appear twice | ||||
| * - every group should have at least two members (edges) | * - every group should have at least two members (edges) | ||||
| * Note: that there can be vertices that only have one group. They are called singularities. | * Note: that there can be vertices that only have one group. They are called singularities. | ||||
| * These vertices will only have one side (there is no way of telling apart front | * These vertices will only have one side (there is no way of telling apart front | ||||
| Context not available. | |||||
| * (tg:<topology group id>)(s:<is split group>,c:<is closed group (before splitting)>) | * (tg:<topology group id>)(s:<is split group>,c:<is closed group (before splitting)>) | ||||
| * } | * } | ||||
| */ | */ | ||||
| gs_ptr = orig_vert_groups_arr; | |||||
| SolidifyCorner **gs_ptr = result->corners_from_vert; | |||||
| for (uint i = 0; i < numVerts; i++, gs_ptr++) { | for (uint i = 0; i < numVerts; i++, gs_ptr++) { | ||||
| EdgeGroup *gs = *gs_ptr; | SolidifyCorner *gs = *gs_ptr; | ||||
| /* check if the vertex is present (may be dissolved because of proximity) */ | /* check if the vertex is present (may be dissolved because of proximity) */ | ||||
| if (gs) { | if (gs) { | ||||
| printf("%d:\n", i); | printf("%d:\n", i); | ||||
| for (EdgeGroup *g = gs; g->valid; g++) { | for (SolidifyCorner *g = gs; g->valid; g++) { | ||||
| NewEdgeRef **e = g->edges; | SolidifyEdge **e = g->edges; | ||||
| for (uint j = 0; j < g->edges_len; j++, e++) { | for (uint j = 0; j < g->edges_len; j++, e++) { | ||||
| printf("%u/%d, ", (*e)->old_edge, (int)(*e)->new_edge); | printf("%u/%d, ", (*e)->orig_edge, (int)(*e)->new_edge); | ||||
| } | } | ||||
| printf("(tg:%u)(s:%u,c:%d)\n", g->topo_group, g->split, g->is_orig_closed); | printf("(tg:%u)(s:%u,c:%d)\n", g->topo_group, g->split, g->is_orig_closed); | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| #endif | #endif | ||||
| /* Make boundary edges/faces. */ | /* Make boundary edges/polys. */ | ||||
| { | { | ||||
| gs_ptr = orig_vert_groups_arr; | SolidifyCorner **gs_ptr = result->corners_from_vert; | ||||
| mv = orig_mvert; | mv = orig_mvert; | ||||
| for (uint i = 0; i < numVerts; i++, gs_ptr++, mv++) { | for (uint i = 0; i < numVerts; i++, gs_ptr++, mv++) { | ||||
| EdgeGroup *gs = *gs_ptr; | SolidifyCorner *gs = *gs_ptr; | ||||
| if (gs) { | if (gs) { | ||||
| EdgeGroup *g = gs; | SolidifyCorner *g = gs; | ||||
| EdgeGroup *g2 = gs; | SolidifyCorner *g2 = gs; | ||||
| EdgeGroup *last_g = NULL; | SolidifyCorner *last_g = NULL; | ||||
| EdgeGroup *first_g = NULL; | SolidifyCorner *first_g = NULL; | ||||
| /* Data calculation cache. */ | /* Data calculation cache. */ | ||||
| char max_crease; | char max_crease; | ||||
| char last_max_crease = 0; | char last_max_crease = 0; | ||||
| Context not available. | |||||
| short last_flag = 0; | short last_flag = 0; | ||||
| short first_flag = 0; | short first_flag = 0; | ||||
| for (uint j = 0; g->valid; g++) { | for (uint j = 0; g->valid; g++) { | ||||
| if ((do_rim && !g->is_orig_closed) || (do_shell && g->split)) { | if ((sctx->do_rim && !g->is_orig_closed) || (sctx->do_shell && g->split)) { | ||||
| max_crease = 0; | max_crease = 0; | ||||
| max_bweight = 0; | max_bweight = 0; | ||||
| flag = 0; | flag = 0; | ||||
| Context not available. | |||||
| BLI_assert(g->edges_len >= 2); | BLI_assert(g->edges_len >= 2); | ||||
| if (g->edges_len == 2) { | if (g->edges_len == 2) { | ||||
| max_crease = min_cc(orig_medge[g->edges[0]->old_edge].crease, | max_crease = min_cc(orig_medge[g->edges[0]->orig_edge].crease, | ||||
| orig_medge[g->edges[1]->old_edge].crease); | orig_medge[g->edges[1]->orig_edge].crease); | ||||
| } | } | ||||
| else { | else { | ||||
| for (uint k = 1; k < g->edges_len - 1; k++) { | for (uint k = 1; k < g->edges_len - 1; k++) { | ||||
| ed = orig_medge + g->edges[k]->old_edge; | ed = orig_medge + g->edges[k]->orig_edge; | ||||
| if (ed->crease > max_crease) { | if (ed->crease > max_crease) { | ||||
| max_crease = ed->crease; | max_crease = ed->crease; | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| const char bweight_open_edge = min_cc( | const char bweight_open_edge = min_cc( | ||||
| orig_medge[g->edges[0]->old_edge].bweight, | orig_medge[g->edges[0]->orig_edge].bweight, | ||||
| orig_medge[g->edges[g->edges_len - 1]->old_edge].bweight); | orig_medge[g->edges[g->edges_len - 1]->orig_edge].bweight); | ||||
| if (bweight_open_edge > 0) { | if (bweight_open_edge > 0) { | ||||
| max_bweight = min_cc(bweight_open_edge, max_bweight); | max_bweight = min_cc(bweight_open_edge, max_bweight); | ||||
| } | } | ||||
| else { | else { | ||||
| if (bevel_convex < 0.0f) { | if (sctx->bevel_convex < 0.0f) { | ||||
| max_bweight = 0; | max_bweight = 0; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| first_flag = flag; | first_flag = flag; | ||||
| } | } | ||||
| else { | else { | ||||
| last_g->open_face_edge = edge_index; | last_g->open_poly_edge = edge_index; | ||||
| CustomData_copy_data(&mesh->edata, | CustomData_copy_data(&mesh->edata, | ||||
| &result->edata, | &result->mesh->edata, | ||||
| (int)last_g->edges[0]->old_edge, | (int)last_g->edges[0]->orig_edge, | ||||
| (int)edge_index, | (int)edge_index, | ||||
| 1); | 1); | ||||
| if (origindex_edge) { | if (origindex_edge) { | ||||
| Context not available. | |||||
| } | } | ||||
| if (!(g + 1)->valid || g->topo_group != (g + 1)->topo_group) { | if (!(g + 1)->valid || g->topo_group != (g + 1)->topo_group) { | ||||
| if (j == 2) { | if (j == 2) { | ||||
| last_g->open_face_edge = edge_index - 1; | last_g->open_poly_edge = edge_index - 1; | ||||
| } | } | ||||
| if (j > 2) { | if (j > 2) { | ||||
| CustomData_copy_data(&mesh->edata, | CustomData_copy_data(&mesh->edata, | ||||
| &result->edata, | &result->mesh->edata, | ||||
| (int)last_g->edges[0]->old_edge, | (int)last_g->edges[0]->orig_edge, | ||||
| (int)edge_index, | (int)edge_index, | ||||
| 1); | 1); | ||||
| if (origindex_edge) { | if (origindex_edge) { | ||||
| origindex_edge[edge_index] = ORIGINDEX_NONE; | origindex_edge[edge_index] = ORIGINDEX_NONE; | ||||
| } | } | ||||
| last_g->open_face_edge = edge_index; | last_g->open_poly_edge = edge_index; | ||||
| medge[edge_index].v1 = last_g->new_vert; | medge[edge_index].v1 = last_g->new_vert; | ||||
| medge[edge_index].v2 = first_g->new_vert; | medge[edge_index].v2 = first_g->new_vert; | ||||
| medge[edge_index].flag = ME_EDGEDRAW | ME_EDGERENDER | | medge[edge_index].flag = ME_EDGEDRAW | ME_EDGERENDER | | ||||
| Context not available. | |||||
| int *loops = MEM_malloc_arrayN(j, sizeof(*loops), "loops in solidify"); | int *loops = MEM_malloc_arrayN(j, sizeof(*loops), "loops in solidify"); | ||||
| /* The #mat_nr is from consensus. */ | /* The #mat_nr is from consensus. */ | ||||
| short most_mat_nr = 0; | short most_mat_nr = 0; | ||||
| uint most_mat_nr_face = 0; | uint most_mat_nr_poly = 0; | ||||
| uint most_mat_nr_count = 0; | uint most_mat_nr_count = 0; | ||||
| for (short l = 0; l < mat_nrs; l++) { | for (short l = 0; l < sctx->mat_nrs; l++) { | ||||
| uint count = 0; | uint count = 0; | ||||
| uint face = 0; | uint poly = 0; | ||||
| uint k = 0; | uint k = 0; | ||||
| for (EdgeGroup *g3 = g2; g3->valid && k < j; g3++) { | for (SolidifyCorner *g3 = g2; g3->valid && k < j; g3++) { | ||||
| if ((do_rim && !g3->is_orig_closed) || (do_shell && g3->split)) { | if ((sctx->do_rim && !g3->is_orig_closed) || (sctx->do_shell && g3->split)) { | ||||
| /* Check both far ends in terms of faces of an edge group. */ | /* Check both far ends in terms of polys of an edge group. */ | ||||
| if (g3->edges[0]->faces[0]->face->mat_nr == l) { | if (g3->edges[0]->polys[0]->poly->mat_nr == l) { | ||||
| face = g3->edges[0]->faces[0]->index; | poly = g3->edges[0]->polys[0]->orig_poly_index; | ||||
| count++; | count++; | ||||
| } | } | ||||
| NewEdgeRef *le = g3->edges[g3->edges_len - 1]; | SolidifyEdge *le = g3->edges[g3->edges_len - 1]; | ||||
| if (le->faces[1] && le->faces[1]->face->mat_nr == l) { | if (le->polys[1] && le->polys[1]->poly->mat_nr == l) { | ||||
| face = le->faces[1]->index; | poly = le->polys[1]->orig_poly_index; | ||||
| count++; | count++; | ||||
| } | } | ||||
| else if (!le->faces[1] && le->faces[0]->face->mat_nr == l) { | else if (!le->polys[1] && le->polys[0]->poly->mat_nr == l) { | ||||
| face = le->faces[0]->index; | poly = le->polys[0]->orig_poly_index; | ||||
| count++; | count++; | ||||
| } | } | ||||
| k++; | k++; | ||||
| Context not available. | |||||
| } | } | ||||
| if (count > most_mat_nr_count) { | if (count > most_mat_nr_count) { | ||||
| most_mat_nr = l; | most_mat_nr = l; | ||||
| most_mat_nr_face = face; | most_mat_nr_poly = poly; | ||||
| most_mat_nr_count = count; | most_mat_nr_count = count; | ||||
| } | } | ||||
| } | } | ||||
| CustomData_copy_data( | CustomData_copy_data( | ||||
| &mesh->pdata, &result->pdata, (int)most_mat_nr_face, (int)poly_index, 1); | &mesh->pdata, &result->mesh->pdata, (int)most_mat_nr_poly, (int)poly_index, 1); | ||||
| if (origindex_poly) { | if (origindex_poly) { | ||||
| origindex_poly[poly_index] = ORIGINDEX_NONE; | origindex_poly[poly_index] = ORIGINDEX_NONE; | ||||
| } | } | ||||
| mpoly[poly_index].loopstart = (int)loop_index; | mpoly[poly_index].loopstart = (int)loop_index; | ||||
| mpoly[poly_index].totloop = (int)j; | mpoly[poly_index].totloop = (int)j; | ||||
| mpoly[poly_index].mat_nr = most_mat_nr + | mpoly[poly_index].mat_nr = most_mat_nr + | ||||
| (g->is_orig_closed || !do_rim ? 0 : mat_ofs_rim); | (g->is_orig_closed || !sctx->do_rim ? 0 : sctx->mat_ofs_rim); | ||||
| CLAMP(mpoly[poly_index].mat_nr, 0, mat_nr_max); | CLAMP(mpoly[poly_index].mat_nr, 0, sctx->mat_nr_max); | ||||
| mpoly[poly_index].flag = orig_mpoly[most_mat_nr_face].flag; | mpoly[poly_index].flag = orig_mpoly[most_mat_nr_poly].flag; | ||||
| poly_index++; | poly_index++; | ||||
| for (uint k = 0; g2->valid && k < j; g2++) { | for (uint k = 0; g2->valid && k < j; g2++) { | ||||
| if ((do_rim && !g2->is_orig_closed) || (do_shell && g2->split)) { | if ((sctx->do_rim && !g2->is_orig_closed) || (sctx->do_shell && g2->split)) { | ||||
| MPoly *face = g2->edges[0]->faces[0]->face; | MPoly *poly = g2->edges[0]->polys[0]->poly; | ||||
| ml = orig_mloop + face->loopstart; | ml = orig_mloop + poly->loopstart; | ||||
| for (int l = 0; l < face->totloop; l++, ml++) { | for (int l = 0; l < poly->totloop; l++, ml++) { | ||||
| if (vm[ml->v] == i) { | if (vm[ml->v] == i) { | ||||
| loops[k] = face->loopstart + l; | loops[k] = poly->loopstart + l; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| if (!do_flip) { | if (!sctx->do_flip) { | ||||
| for (uint k = 0; k < j; k++) { | for (uint k = 0; k < j; k++) { | ||||
| CustomData_copy_data(&mesh->ldata, &result->ldata, loops[k], (int)loop_index, 1); | CustomData_copy_data( | ||||
| &mesh->ldata, &result->mesh->ldata, loops[k], (int)loop_index, 1); | |||||
| mloop[loop_index].v = medge[edge_index - j + k].v1; | mloop[loop_index].v = medge[edge_index - j + k].v1; | ||||
| mloop[loop_index++].e = edge_index - j + k; | mloop[loop_index++].e = edge_index - j + k; | ||||
| } | } | ||||
| Context not available. | |||||
| else { | else { | ||||
| for (uint k = 1; k <= j; k++) { | for (uint k = 1; k <= j; k++) { | ||||
| CustomData_copy_data( | CustomData_copy_data( | ||||
| &mesh->ldata, &result->ldata, loops[j - k], (int)loop_index, 1); | &mesh->ldata, &result->mesh->ldata, loops[j - k], (int)loop_index, 1); | ||||
| mloop[loop_index].v = medge[edge_index - k].v2; | mloop[loop_index].v = medge[edge_index - k].v2; | ||||
| mloop[loop_index++].e = edge_index - k; | mloop[loop_index++].e = edge_index - k; | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| /* Make boundary faces. */ | /* Make boundary polys. */ | ||||
| if (do_rim) { | if (sctx->do_rim) { | ||||
| for (uint i = 0; i < numEdges; i++) { | for (uint i = 0; i < numEdges; i++) { | ||||
| if (edge_adj_faces_len[i] == 1 && orig_edge_data_arr[i] && | if (sctx->edge_adj_polys_len[i] == 1 && result->edges[i] && (*result->edges[i])->orig_edge == i) { | ||||
| (*orig_edge_data_arr[i])->old_edge == i) { | SolidifyEdge **new_edges = result->edges[i]; | ||||
| NewEdgeRef **new_edges = orig_edge_data_arr[i]; | |||||
| SolidifyEdge *edge1 = new_edges[0]; | |||||
| NewEdgeRef *edge1 = new_edges[0]; | SolidifyEdge *edge2 = new_edges[1]; | ||||
| NewEdgeRef *edge2 = new_edges[1]; | const bool v1_singularity = edge1->link_corners[0]->is_singularity; | ||||
| const bool v1_singularity = edge1->link_edge_groups[0]->is_singularity; | const bool v2_singularity = edge1->link_corners[1]->is_singularity; | ||||
| const bool v2_singularity = edge1->link_edge_groups[1]->is_singularity; | |||||
| if (v1_singularity && v2_singularity) { | if (v1_singularity && v2_singularity) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| MPoly *face = (*new_edges)->faces[0]->face; | MPoly *poly = (*new_edges)->polys[0]->poly; | ||||
| CustomData_copy_data( | CustomData_copy_data(&mesh->pdata, | ||||
| &mesh->pdata, &result->pdata, (int)(*new_edges)->faces[0]->index, (int)poly_index, 1); | &result->mesh->pdata, | ||||
| (int)(*new_edges)->polys[0]->orig_poly_index, | |||||
| (int)poly_index, | |||||
| 1); | |||||
| mpoly[poly_index].loopstart = (int)loop_index; | mpoly[poly_index].loopstart = (int)loop_index; | ||||
| mpoly[poly_index].totloop = 4 - (int)(v1_singularity || v2_singularity); | mpoly[poly_index].totloop = 4 - (int)(v1_singularity || v2_singularity); | ||||
| mpoly[poly_index].mat_nr = face->mat_nr + mat_ofs_rim; | mpoly[poly_index].mat_nr = poly->mat_nr + sctx->mat_ofs_rim; | ||||
| CLAMP(mpoly[poly_index].mat_nr, 0, mat_nr_max); | CLAMP(mpoly[poly_index].mat_nr, 0, sctx->mat_nr_max); | ||||
| mpoly[poly_index].flag = face->flag; | mpoly[poly_index].flag = poly->flag; | ||||
| poly_index++; | poly_index++; | ||||
| int loop1 = -1; | int loop1 = -1; | ||||
| int loop2 = -1; | int loop2 = -1; | ||||
| ml = orig_mloop + face->loopstart; | ml = orig_mloop + poly->loopstart; | ||||
| const uint old_v1 = vm[orig_medge[edge1->old_edge].v1]; | const uint orig_v1 = vm[orig_medge[edge1->orig_edge].v1]; | ||||
| const uint old_v2 = vm[orig_medge[edge1->old_edge].v2]; | const uint orig_v2 = vm[orig_medge[edge1->orig_edge].v2]; | ||||
| for (uint j = 0; j < face->totloop; j++, ml++) { | for (uint j = 0; j < poly->totloop; j++, ml++) { | ||||
| if (vm[ml->v] == old_v1) { | if (vm[ml->v] == orig_v1) { | ||||
| loop1 = face->loopstart + (int)j; | loop1 = poly->loopstart + (int)j; | ||||
| } | } | ||||
| else if (vm[ml->v] == old_v2) { | else if (vm[ml->v] == orig_v2) { | ||||
| loop2 = face->loopstart + (int)j; | loop2 = poly->loopstart + (int)j; | ||||
| } | } | ||||
| } | } | ||||
| BLI_assert(loop1 != -1 && loop2 != -1); | BLI_assert(loop1 != -1 && loop2 != -1); | ||||
| MEdge *open_face_edge; | MEdge *open_poly_edge; | ||||
| uint open_face_edge_index; | uint open_poly_edge_index; | ||||
| if (!do_flip) { | if (!sctx->do_flip) { | ||||
| if (rim_defgrp_index != -1) { | if (sctx->rim_defgrp_index != -1) { | ||||
| BKE_defvert_ensure_index(&result->dvert[medge[edge1->new_edge].v1], rim_defgrp_index) | BKE_defvert_ensure_index(&result->mesh->dvert[medge[edge1->new_edge].v1], | ||||
| sctx->rim_defgrp_index) | |||||
| ->weight = 1.0f; | ->weight = 1.0f; | ||||
| } | } | ||||
| CustomData_copy_data(&mesh->ldata, &result->ldata, loop1, (int)loop_index, 1); | CustomData_copy_data(&mesh->ldata, &result->mesh->ldata, loop1, (int)loop_index, 1); | ||||
| mloop[loop_index].v = medge[edge1->new_edge].v1; | mloop[loop_index].v = medge[edge1->new_edge].v1; | ||||
| mloop[loop_index++].e = edge1->new_edge; | mloop[loop_index++].e = edge1->new_edge; | ||||
| if (!v2_singularity) { | if (!v2_singularity) { | ||||
| open_face_edge_index = edge1->link_edge_groups[1]->open_face_edge; | open_poly_edge_index = edge1->link_corners[1]->open_poly_edge; | ||||
| if (rim_defgrp_index != -1) { | if (sctx->rim_defgrp_index != -1) { | ||||
| BKE_defvert_ensure_index(&result->dvert[medge[edge1->new_edge].v2], rim_defgrp_index) | BKE_defvert_ensure_index(&result->mesh->dvert[medge[edge1->new_edge].v2], | ||||
| sctx->rim_defgrp_index) | |||||
| ->weight = 1.0f; | ->weight = 1.0f; | ||||
| } | } | ||||
| CustomData_copy_data(&mesh->ldata, &result->ldata, loop2, (int)loop_index, 1); | CustomData_copy_data(&mesh->ldata, &result->mesh->ldata, loop2, (int)loop_index, 1); | ||||
| mloop[loop_index].v = medge[edge1->new_edge].v2; | mloop[loop_index].v = medge[edge1->new_edge].v2; | ||||
| open_face_edge = medge + open_face_edge_index; | open_poly_edge = medge + open_poly_edge_index; | ||||
| if (ELEM(medge[edge2->new_edge].v2, open_face_edge->v1, open_face_edge->v2)) { | if (ELEM(medge[edge2->new_edge].v2, open_poly_edge->v1, open_poly_edge->v2)) { | ||||
| mloop[loop_index++].e = open_face_edge_index; | mloop[loop_index++].e = open_poly_edge_index; | ||||
| } | } | ||||
| else { | else { | ||||
| mloop[loop_index++].e = edge2->link_edge_groups[1]->open_face_edge; | mloop[loop_index++].e = edge2->link_corners[1]->open_poly_edge; | ||||
| } | } | ||||
| } | } | ||||
| if (rim_defgrp_index != -1) { | if (sctx->rim_defgrp_index != -1) { | ||||
| BKE_defvert_ensure_index(&result->dvert[medge[edge2->new_edge].v2], rim_defgrp_index) | BKE_defvert_ensure_index(&result->mesh->dvert[medge[edge2->new_edge].v2], | ||||
| sctx->rim_defgrp_index) | |||||
| ->weight = 1.0f; | ->weight = 1.0f; | ||||
| } | } | ||||
| CustomData_copy_data(&mesh->ldata, &result->ldata, loop2, (int)loop_index, 1); | CustomData_copy_data(&mesh->ldata, &result->mesh->ldata, loop2, (int)loop_index, 1); | ||||
| mloop[loop_index].v = medge[edge2->new_edge].v2; | mloop[loop_index].v = medge[edge2->new_edge].v2; | ||||
| mloop[loop_index++].e = edge2->new_edge; | mloop[loop_index++].e = edge2->new_edge; | ||||
| if (!v1_singularity) { | if (!v1_singularity) { | ||||
| open_face_edge_index = edge2->link_edge_groups[0]->open_face_edge; | open_poly_edge_index = edge2->link_corners[0]->open_poly_edge; | ||||
| if (rim_defgrp_index != -1) { | if (sctx->rim_defgrp_index != -1) { | ||||
| BKE_defvert_ensure_index(&result->dvert[medge[edge2->new_edge].v1], rim_defgrp_index) | BKE_defvert_ensure_index(&result->mesh->dvert[medge[edge2->new_edge].v1], | ||||
| sctx->rim_defgrp_index) | |||||
| ->weight = 1.0f; | ->weight = 1.0f; | ||||
| } | } | ||||
| CustomData_copy_data(&mesh->ldata, &result->ldata, loop1, (int)loop_index, 1); | CustomData_copy_data(&mesh->ldata, &result->mesh->ldata, loop1, (int)loop_index, 1); | ||||
| mloop[loop_index].v = medge[edge2->new_edge].v1; | mloop[loop_index].v = medge[edge2->new_edge].v1; | ||||
| open_face_edge = medge + open_face_edge_index; | open_poly_edge = medge + open_poly_edge_index; | ||||
| if (ELEM(medge[edge1->new_edge].v1, open_face_edge->v1, open_face_edge->v2)) { | if (ELEM(medge[edge1->new_edge].v1, open_poly_edge->v1, open_poly_edge->v2)) { | ||||
| mloop[loop_index++].e = open_face_edge_index; | mloop[loop_index++].e = open_poly_edge_index; | ||||
| } | } | ||||
| else { | else { | ||||
| mloop[loop_index++].e = edge1->link_edge_groups[0]->open_face_edge; | mloop[loop_index++].e = edge1->link_corners[0]->open_poly_edge; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if (!v1_singularity) { | if (!v1_singularity) { | ||||
| open_face_edge_index = edge1->link_edge_groups[0]->open_face_edge; | open_poly_edge_index = edge1->link_corners[0]->open_poly_edge; | ||||
| if (rim_defgrp_index != -1) { | if (sctx->rim_defgrp_index != -1) { | ||||
| BKE_defvert_ensure_index(&result->dvert[medge[edge1->new_edge].v1], rim_defgrp_index) | BKE_defvert_ensure_index(&result->mesh->dvert[medge[edge1->new_edge].v1], | ||||
| sctx->rim_defgrp_index) | |||||
| ->weight = 1.0f; | ->weight = 1.0f; | ||||
| } | } | ||||
| CustomData_copy_data(&mesh->ldata, &result->ldata, loop1, (int)loop_index, 1); | CustomData_copy_data(&mesh->ldata, &result->mesh->ldata, loop1, (int)loop_index, 1); | ||||
| mloop[loop_index].v = medge[edge1->new_edge].v1; | mloop[loop_index].v = medge[edge1->new_edge].v1; | ||||
| open_face_edge = medge + open_face_edge_index; | open_poly_edge = medge + open_poly_edge_index; | ||||
| if (ELEM(medge[edge2->new_edge].v1, open_face_edge->v1, open_face_edge->v2)) { | if (ELEM(medge[edge2->new_edge].v1, open_poly_edge->v1, open_poly_edge->v2)) { | ||||
| mloop[loop_index++].e = open_face_edge_index; | mloop[loop_index++].e = open_poly_edge_index; | ||||
| } | } | ||||
| else { | else { | ||||
| mloop[loop_index++].e = edge2->link_edge_groups[0]->open_face_edge; | mloop[loop_index++].e = edge2->link_corners[0]->open_poly_edge; | ||||
| } | } | ||||
| } | } | ||||
| if (rim_defgrp_index != -1) { | if (sctx->rim_defgrp_index != -1) { | ||||
| BKE_defvert_ensure_index(&result->dvert[medge[edge2->new_edge].v1], rim_defgrp_index) | BKE_defvert_ensure_index(&result->mesh->dvert[medge[edge2->new_edge].v1], | ||||
| sctx->rim_defgrp_index) | |||||
| ->weight = 1.0f; | ->weight = 1.0f; | ||||
| } | } | ||||
| CustomData_copy_data(&mesh->ldata, &result->ldata, loop1, (int)loop_index, 1); | CustomData_copy_data(&mesh->ldata, &result->mesh->ldata, loop1, (int)loop_index, 1); | ||||
| mloop[loop_index].v = medge[edge2->new_edge].v1; | mloop[loop_index].v = medge[edge2->new_edge].v1; | ||||
| mloop[loop_index++].e = edge2->new_edge; | mloop[loop_index++].e = edge2->new_edge; | ||||
| if (!v2_singularity) { | if (!v2_singularity) { | ||||
| open_face_edge_index = edge2->link_edge_groups[1]->open_face_edge; | open_poly_edge_index = edge2->link_corners[1]->open_poly_edge; | ||||
| if (rim_defgrp_index != -1) { | if (sctx->rim_defgrp_index != -1) { | ||||
| BKE_defvert_ensure_index(&result->dvert[medge[edge2->new_edge].v2], rim_defgrp_index) | BKE_defvert_ensure_index(&result->mesh->dvert[medge[edge2->new_edge].v2], | ||||
| sctx->rim_defgrp_index) | |||||
| ->weight = 1.0f; | ->weight = 1.0f; | ||||
| } | } | ||||
| CustomData_copy_data(&mesh->ldata, &result->ldata, loop2, (int)loop_index, 1); | CustomData_copy_data(&mesh->ldata, &result->mesh->ldata, loop2, (int)loop_index, 1); | ||||
| mloop[loop_index].v = medge[edge2->new_edge].v2; | mloop[loop_index].v = medge[edge2->new_edge].v2; | ||||
| open_face_edge = medge + open_face_edge_index; | open_poly_edge = medge + open_poly_edge_index; | ||||
| if (ELEM(medge[edge1->new_edge].v2, open_face_edge->v1, open_face_edge->v2)) { | if (ELEM(medge[edge1->new_edge].v2, open_poly_edge->v1, open_poly_edge->v2)) { | ||||
| mloop[loop_index++].e = open_face_edge_index; | mloop[loop_index++].e = open_poly_edge_index; | ||||
| } | } | ||||
| else { | else { | ||||
| mloop[loop_index++].e = edge1->link_edge_groups[1]->open_face_edge; | mloop[loop_index++].e = edge1->link_corners[1]->open_poly_edge; | ||||
| } | } | ||||
| } | } | ||||
| if (rim_defgrp_index != -1) { | if (sctx->rim_defgrp_index != -1) { | ||||
| BKE_defvert_ensure_index(&result->dvert[medge[edge1->new_edge].v2], rim_defgrp_index) | BKE_defvert_ensure_index(&result->mesh->dvert[medge[edge1->new_edge].v2], | ||||
| sctx->rim_defgrp_index) | |||||
| ->weight = 1.0f; | ->weight = 1.0f; | ||||
| } | } | ||||
| CustomData_copy_data(&mesh->ldata, &result->ldata, loop2, (int)loop_index, 1); | CustomData_copy_data(&mesh->ldata, &result->mesh->ldata, loop2, (int)loop_index, 1); | ||||
| mloop[loop_index].v = medge[edge1->new_edge].v2; | mloop[loop_index].v = medge[edge1->new_edge].v2; | ||||
| mloop[loop_index++].e = edge1->new_edge; | mloop[loop_index++].e = edge1->new_edge; | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| /* Make faces. */ | /* Make polys. */ | ||||
| if (do_shell) { | if (sctx->do_shell) { | ||||
| NewFaceRef *fr = face_sides_arr; | SolidifyPoly *fr = result->polys; | ||||
| uint *face_loops = MEM_malloc_arrayN( | uint *poly_loops = MEM_malloc_arrayN( | ||||
| largest_ngon * 2, sizeof(*face_loops), "face_loops in solidify"); | sctx->largest_ngon * 2, sizeof(*poly_loops), "poly_loops in solidify"); | ||||
| uint *face_verts = MEM_malloc_arrayN( | uint *poly_verts = MEM_malloc_arrayN( | ||||
| largest_ngon * 2, sizeof(*face_verts), "face_verts in solidify"); | sctx->largest_ngon * 2, sizeof(*poly_verts), "poly_verts in solidify"); | ||||
| uint *face_edges = MEM_malloc_arrayN( | uint *poly_edges = MEM_malloc_arrayN( | ||||
| largest_ngon * 2, sizeof(*face_edges), "face_edges in solidify"); | sctx->largest_ngon * 2, sizeof(*poly_edges), "poly_edges in solidify"); | ||||
| for (uint i = 0; i < numPolys * 2; i++, fr++) { | for (uint i = 0; i < numPolys * 2; i++, fr++) { | ||||
| const uint loopstart = (uint)fr->face->loopstart; | const uint loopstart = (uint)fr->poly->loopstart; | ||||
| uint totloop = (uint)fr->face->totloop; | uint totloop = (uint)fr->poly->totloop; | ||||
| uint valid_edges = 0; | uint valid_edges = 0; | ||||
| uint k = 0; | uint k = 0; | ||||
| while (totloop > 0 && (!fr->link_edges[totloop - 1] || | while (totloop > 0 && (!fr->link_edges[totloop - 1] || | ||||
| Context not available. | |||||
| totloop--; | totloop--; | ||||
| } | } | ||||
| if (totloop > 0) { | if (totloop > 0) { | ||||
| NewEdgeRef *prior_edge = fr->link_edges[totloop - 1]; | SolidifyEdge *prior_edge = fr->link_edges[totloop - 1]; | ||||
| uint prior_flip = (uint)(vm[orig_medge[prior_edge->old_edge].v1] == | uint prior_flip = (uint)(vm[orig_medge[prior_edge->orig_edge].v1] == | ||||
| vm[orig_mloop[loopstart + (totloop - 1)].v]); | vm[orig_mloop[loopstart + (totloop - 1)].v]); | ||||
| for (uint j = 0; j < totloop; j++) { | for (uint j = 0; j < totloop; j++) { | ||||
| NewEdgeRef *new_edge = fr->link_edges[j]; | SolidifyEdge *new_edge = fr->link_edges[j]; | ||||
| if (new_edge && new_edge->new_edge != MOD_SOLIDIFY_EMPTY_TAG) { | if (new_edge && new_edge->new_edge != MOD_SOLIDIFY_EMPTY_TAG) { | ||||
| valid_edges++; | valid_edges++; | ||||
| const uint flip = (uint)(vm[orig_medge[new_edge->old_edge].v2] == | const uint flip = (uint)(vm[orig_medge[new_edge->orig_edge].v2] == | ||||
| vm[orig_mloop[loopstart + j].v]); | vm[orig_mloop[loopstart + j].v]); | ||||
| BLI_assert(flip || | BLI_assert(flip || | ||||
| vm[orig_medge[new_edge->old_edge].v1] == vm[orig_mloop[loopstart + j].v]); | vm[orig_medge[new_edge->orig_edge].v1] == vm[orig_mloop[loopstart + j].v]); | ||||
| /* The vert thats in the current loop. */ | /* The vert thats in the current loop. */ | ||||
| const uint new_v1 = new_edge->link_edge_groups[flip]->new_vert; | const uint new_v1 = new_edge->link_corners[flip]->new_vert; | ||||
| /* The vert thats in the next loop. */ | /* The vert thats in the next loop. */ | ||||
| const uint new_v2 = new_edge->link_edge_groups[1 - flip]->new_vert; | const uint new_v2 = new_edge->link_corners[1 - flip]->new_vert; | ||||
| if (k == 0 || face_verts[k - 1] != new_v1) { | if (k == 0 || poly_verts[k - 1] != new_v1) { | ||||
| face_loops[k] = loopstart + j; | poly_loops[k] = loopstart + j; | ||||
| if (fr->reversed) { | if (fr->reversed) { | ||||
| face_edges[k] = prior_edge->link_edge_groups[prior_flip]->open_face_edge; | poly_edges[k] = prior_edge->link_corners[prior_flip]->open_poly_edge; | ||||
| } | } | ||||
| else { | else { | ||||
| face_edges[k] = new_edge->link_edge_groups[flip]->open_face_edge; | poly_edges[k] = new_edge->link_corners[flip]->open_poly_edge; | ||||
| } | } | ||||
| BLI_assert(k == 0 || medge[face_edges[k]].v2 == face_verts[k - 1] || | BLI_assert(k == 0 || medge[poly_edges[k]].v2 == poly_verts[k - 1] || | ||||
| medge[face_edges[k]].v1 == face_verts[k - 1]); | medge[poly_edges[k]].v1 == poly_verts[k - 1]); | ||||
| BLI_assert(face_edges[k] == MOD_SOLIDIFY_EMPTY_TAG || | BLI_assert(poly_edges[k] == MOD_SOLIDIFY_EMPTY_TAG || | ||||
| medge[face_edges[k]].v2 == new_v1 || medge[face_edges[k]].v1 == new_v1); | medge[poly_edges[k]].v2 == new_v1 || medge[poly_edges[k]].v1 == new_v1); | ||||
| face_verts[k++] = new_v1; | poly_verts[k++] = new_v1; | ||||
| } | } | ||||
| prior_edge = new_edge; | prior_edge = new_edge; | ||||
| prior_flip = 1 - flip; | prior_flip = 1 - flip; | ||||
| if (j < totloop - 1 || face_verts[0] != new_v2) { | if (j < totloop - 1 || poly_verts[0] != new_v2) { | ||||
| face_loops[k] = loopstart + (j + 1) % totloop; | poly_loops[k] = loopstart + (j + 1) % totloop; | ||||
| face_edges[k] = new_edge->new_edge; | poly_edges[k] = new_edge->new_edge; | ||||
| face_verts[k++] = new_v2; | poly_verts[k++] = new_v2; | ||||
| } | } | ||||
| else { | else { | ||||
| face_edges[0] = new_edge->new_edge; | poly_edges[0] = new_edge->new_edge; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (k > 2 && valid_edges > 2) { | if (k > 2 && valid_edges > 2) { | ||||
| CustomData_copy_data(&mesh->pdata, &result->pdata, (int)(i / 2), (int)poly_index, 1); | CustomData_copy_data( | ||||
| &mesh->pdata, &result->mesh->pdata, (int)(i / 2), (int)poly_index, 1); | |||||
| mpoly[poly_index].loopstart = (int)loop_index; | mpoly[poly_index].loopstart = (int)loop_index; | ||||
| mpoly[poly_index].totloop = (int)k; | mpoly[poly_index].totloop = (int)k; | ||||
| mpoly[poly_index].mat_nr = fr->face->mat_nr + (fr->reversed ? mat_ofs : 0); | mpoly[poly_index].mat_nr = fr->poly->mat_nr + (fr->reversed ? sctx->mat_ofs : 0); | ||||
| CLAMP(mpoly[poly_index].mat_nr, 0, mat_nr_max); | CLAMP(mpoly[poly_index].mat_nr, 0, sctx->mat_nr_max); | ||||
| mpoly[poly_index].flag = fr->face->flag; | mpoly[poly_index].flag = fr->poly->flag; | ||||
| if (fr->reversed != do_flip) { | if (fr->reversed != sctx->do_flip) { | ||||
| for (int l = (int)k - 1; l >= 0; l--) { | for (int l = (int)k - 1; l >= 0; l--) { | ||||
| if (shell_defgrp_index != -1) { | if (sctx->shell_defgrp_index != -1) { | ||||
| BKE_defvert_ensure_index(&result->dvert[face_verts[l]], shell_defgrp_index) | BKE_defvert_ensure_index(&result->mesh->dvert[poly_verts[l]], sctx->shell_defgrp_index) | ||||
| ->weight = 1.0f; | ->weight = 1.0f; | ||||
| } | } | ||||
| CustomData_copy_data( | CustomData_copy_data( | ||||
| &mesh->ldata, &result->ldata, (int)face_loops[l], (int)loop_index, 1); | &mesh->ldata, &result->mesh->ldata, (int)poly_loops[l], (int)loop_index, 1); | ||||
| mloop[loop_index].v = face_verts[l]; | mloop[loop_index].v = poly_verts[l]; | ||||
| mloop[loop_index++].e = face_edges[l]; | mloop[loop_index++].e = poly_edges[l]; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| uint l = k - 1; | uint l = k - 1; | ||||
| for (uint next_l = 0; next_l < k; next_l++) { | for (uint next_l = 0; next_l < k; next_l++) { | ||||
| CustomData_copy_data( | CustomData_copy_data( | ||||
| &mesh->ldata, &result->ldata, (int)face_loops[l], (int)loop_index, 1); | &mesh->ldata, &result->mesh->ldata, (int)poly_loops[l], (int)loop_index, 1); | ||||
| mloop[loop_index].v = face_verts[l]; | mloop[loop_index].v = poly_verts[l]; | ||||
| mloop[loop_index++].e = face_edges[next_l]; | mloop[loop_index++].e = poly_edges[next_l]; | ||||
| l = next_l; | l = next_l; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(face_loops); | MEM_freeN(poly_loops); | ||||
| MEM_freeN(face_verts); | MEM_freeN(poly_verts); | ||||
| MEM_freeN(face_edges); | MEM_freeN(poly_edges); | ||||
| } | } | ||||
| if (edge_index != numNewEdges) { | if (edge_index != result->numEdges) { | ||||
| BKE_modifier_set_error( | BKE_modifier_set_error((ModifierData *)smd, | ||||
| md, "Internal Error: edges array wrong size: %u instead of %u", numNewEdges, edge_index); | "Internal Error: edges array wrong size: %u instead of %u", | ||||
| result->numEdges, | |||||
| edge_index); | |||||
| } | } | ||||
| if (poly_index != numNewPolys) { | if (poly_index != result->numPolys) { | ||||
| BKE_modifier_set_error( | BKE_modifier_set_error((ModifierData *)smd, | ||||
| md, "Internal Error: polys array wrong size: %u instead of %u", numNewPolys, poly_index); | "Internal Error: polys array wrong size: %u instead of %u", | ||||
| result->numPolys, | |||||
| poly_index); | |||||
| } | } | ||||
| if (loop_index != numNewLoops) { | if (loop_index != result->numLoops) { | ||||
| BKE_modifier_set_error( | BKE_modifier_set_error((ModifierData *)smd, | ||||
| md, "Internal Error: loops array wrong size: %u instead of %u", numNewLoops, loop_index); | "Internal Error: loops array wrong size: %u instead of %u", | ||||
| result->numLoops, | |||||
| loop_index); | |||||
| } | } | ||||
| BLI_assert(edge_index == numNewEdges); | BLI_assert(edge_index == result->numEdges); | ||||
| BLI_assert(poly_index == numNewPolys); | BLI_assert(poly_index == result->numPolys); | ||||
| BLI_assert(loop_index == numNewLoops); | BLI_assert(loop_index == result->numLoops); | ||||
| } | |||||
| /* Free remaining memory */ | |||||
| { | static void solidify_free_context(SolidifyContext *sctx) { | ||||
| MEM_freeN(vm); | const uint numVerts = (uint)sctx->mesh->totvert; | ||||
| MEM_freeN(edge_adj_faces_len); | const uint numEdges = (uint)sctx->mesh->totedge; | ||||
| uint i = 0; | const uint numPolys = (uint)sctx->mesh->totpoly; | ||||
| for (EdgeGroup **p = orig_vert_groups_arr; i < numVerts; i++, p++) { | |||||
| if (*p) { | MEM_freeN(sctx->vm); | ||||
| for (EdgeGroup *eg = *p; eg->valid; eg++) { | MEM_freeN(sctx->edge_adj_polys_len); | ||||
| MEM_freeN(eg->edges); | uint i = 0; | ||||
| } | for (SolidifyCorner **p = sctx->result->corners_from_vert; i < numVerts; i++, p++) { | ||||
| MEM_freeN(*p); | if (*p) { | ||||
| for (SolidifyCorner *c = *p; c->valid; c++) { | |||||
| MEM_freeN(c->edges); | |||||
| } | } | ||||
| MEM_freeN(*p); | |||||
| } | } | ||||
| MEM_freeN(orig_vert_groups_arr); | } | ||||
| i = numEdges; | MEM_freeN(sctx->result->corners_from_vert); | ||||
| for (NewEdgeRef ***p = orig_edge_data_arr + (numEdges - 1); i > 0; i--, p--) { | i = numEdges; | ||||
| if (*p && (**p)->old_edge == i - 1) { | for (SolidifyEdge ***p = sctx->result->edges + (numEdges - 1); i > 0; i--, p--) { | ||||
| for (NewEdgeRef **l = *p; *l; l++) { | if (*p && (**p)->orig_edge == i - 1) { | ||||
| MEM_freeN(*l); | for (SolidifyEdge **l = *p; *l; l++) { | ||||
| } | MEM_freeN(*l); | ||||
| MEM_freeN(*p); | |||||
| } | } | ||||
| MEM_freeN(*p); | |||||
| } | } | ||||
| MEM_freeN(orig_edge_data_arr); | } | ||||
| MEM_freeN(orig_edge_lengths); | MEM_freeN(sctx->result->edges); | ||||
| i = 0; | MEM_freeN(sctx->orig_edge_lengths); | ||||
| for (NewFaceRef *p = face_sides_arr; i < numPolys * 2; i++, p++) { | i = 0; | ||||
| MEM_freeN(p->link_edges); | for (SolidifyPoly *p = sctx->result->polys; i < numPolys * 2; i++, p++) { | ||||
| MEM_freeN(p->link_edges); | |||||
| } | |||||
| MEM_freeN(sctx->result->polys); | |||||
| MEM_freeN(sctx->poly_nors); | |||||
| } | |||||
| /** \} */ | |||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Main Solidify Function | |||||
| * \{ */ | |||||
| Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, | |||||
| const ModifierEvalContext *ctx, | |||||
| Mesh *mesh) | |||||
| { | |||||
| SolidifyModifierData *smd = (SolidifyModifierData *)md; | |||||
| MVert *orig_mvert; | |||||
| MLoop *orig_mloop; | |||||
| MPoly *orig_mpoly; | |||||
| const uint numVerts = (uint)mesh->totvert; | |||||
| const uint numEdges = (uint)mesh->totedge; | |||||
| const uint numPolys = (uint)mesh->totpoly; | |||||
| const uint numLoops = (uint)mesh->totloop; | |||||
| if (numPolys == 0 && numVerts != 0) { | |||||
| return mesh; | |||||
| } | |||||
| orig_mvert = mesh->mvert; | |||||
| orig_mloop = mesh->mloop; | |||||
| orig_mpoly = mesh->mpoly; | |||||
| /* Create solidify mesh. */ | |||||
| SolidifyMesh result_data = (SolidifyMesh){ | |||||
| .numVerts = 0, | |||||
| .numEdges = 0, | |||||
| .numLoops = 0, | |||||
| .numPolys = 0, | |||||
| .has_singularities = false, | |||||
| }; | |||||
| SolidifyMesh *result = &result_data; | |||||
| /* Create solidify context. */ | |||||
| SolidifyContext sctx_data = (SolidifyContext){ | |||||
| .smd = smd, | |||||
| .mesh = mesh, | |||||
| .result = result, | |||||
| }; | |||||
| SolidifyContext *sctx = &sctx_data; | |||||
| /* Only use material offsets if we have 2 or more materials. */ | |||||
| sctx->mat_nrs = ctx->object->totcol > 1 ? ctx->object->totcol : 1; | |||||
| sctx->mat_nr_max = sctx->mat_nrs - 1; | |||||
| sctx->mat_ofs = sctx->mat_nrs > 1 ? smd->mat_ofs : 0; | |||||
| sctx->mat_ofs_rim = sctx->mat_nrs > 1 ? smd->mat_ofs_rim : 0; | |||||
| sctx->ofs_front = (smd->offset_fac + 1.0f) * 0.5f * smd->offset; | |||||
| sctx->ofs_back = sctx->ofs_front - smd->offset * smd->offset_fac; | |||||
| sctx->ofs_front_clamped = max_ff(1e-5f, fabsf(smd->offset > 0 ? sctx->ofs_front : sctx->ofs_back)); | |||||
| sctx->ofs_back_clamped = max_ff(1e-5f, fabsf(smd->offset > 0 ? sctx->ofs_back : sctx->ofs_front)); | |||||
| sctx->offset_fac_vg = smd->offset_fac_vg; | |||||
| sctx->offset_fac_vg_inv = 1.0f - smd->offset_fac_vg; | |||||
| sctx->offset = fabsf(smd->offset) * smd->offset_clamp; | |||||
| sctx->do_angle_clamp = smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP; | |||||
| sctx->do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0; | |||||
| sctx->do_rim = smd->flag & MOD_SOLIDIFY_RIM; | |||||
| sctx->do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == | |||||
| 0; | |||||
| sctx->do_clamp = (smd->offset_clamp != 0.0f); | |||||
| sctx->bevel_convex = smd->bevel_convex; | |||||
| sctx->defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0; | |||||
| sctx->shell_defgrp_index = BKE_object_defgroup_name_index(ctx->object, | |||||
| smd->shell_defgrp_name); | |||||
| sctx->rim_defgrp_index = BKE_object_defgroup_name_index(ctx->object, smd->rim_defgrp_name); | |||||
| MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &sctx->dvert, &sctx->defgrp_index); | |||||
| sctx->do_flat_faces = sctx->dvert && (smd->flag & MOD_SOLIDIFY_NONMANIFOLD_FLAT_FACES); | |||||
| /* Calculate only poly normals. */ | |||||
| float(*poly_nors)[3] = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__); | |||||
| sctx->poly_nors = poly_nors; | |||||
| BKE_mesh_calc_normals_poly(orig_mvert, | |||||
| NULL, | |||||
| (int)numVerts, | |||||
| orig_mloop, | |||||
| orig_mpoly, | |||||
| (int)numLoops, | |||||
| (int)numPolys, | |||||
| poly_nors, | |||||
| true); | |||||
| sctx->null_polys = | |||||
| (smd->nonmanifold_offset_mode == MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS) ? | |||||
| MEM_calloc_arrayN(numPolys, sizeof(*sctx->null_polys), "null_polys in solidify") : | |||||
| NULL; | |||||
| /* Prepare the mesh data by preprocessing the vertices and recognizing the topology. */ | |||||
| solidify_prepare_mesh_structure(sctx); | |||||
| /* TODO create_regions if fix_intersections. */ | |||||
| /* Write the calculated vertex coordinates into the prepared mesh structure. */ | |||||
| solidify_set_new_vertex_coordinates(sctx); | |||||
| /* TODO create vertdata for intersection fixes (intersection fixing per topology region). */ | |||||
| /* Correction for adjacent one sided groups around a vert to | |||||
| * prevent edge duplicates and null polys. */ | |||||
| uint(*singularity_edges)[2] = NULL; | |||||
| uint totsingularity = 0; | |||||
| if (result->has_singularities) { | |||||
| result->has_singularities = false; | |||||
| uint i = 0; | |||||
| uint singularity_edges_len = 1; | |||||
| singularity_edges = MEM_malloc_arrayN( | |||||
| singularity_edges_len, sizeof(*singularity_edges), "singularity_edges in solidify"); | |||||
| for (SolidifyEdge ***new_edges = result->edges; i < numEdges; i++, new_edges++) { | |||||
| if (*new_edges && (sctx->do_shell || sctx->edge_adj_polys_len[i] == 1) && | |||||
| (**new_edges)->orig_edge == i) { | |||||
| for (SolidifyEdge **l = *new_edges; *l; l++) { | |||||
| if ((*l)->link_corners[0]->is_singularity && (*l)->link_corners[1]->is_singularity) { | |||||
| const uint v1 = (*l)->link_corners[0]->new_vert; | |||||
| const uint v2 = (*l)->link_corners[1]->new_vert; | |||||
| bool exists_already = false; | |||||
| uint j = 0; | |||||
| for (uint(*p)[2] = singularity_edges; j < totsingularity; p++, j++) { | |||||
| if (((*p)[0] == v1 && (*p)[1] == v2) || ((*p)[0] == v2 && (*p)[1] == v1)) { | |||||
| exists_already = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (!exists_already) { | |||||
| result->has_singularities = true; | |||||
| if (singularity_edges_len <= totsingularity) { | |||||
| singularity_edges_len = totsingularity + 1; | |||||
| singularity_edges = MEM_reallocN_id(singularity_edges, | |||||
| singularity_edges_len * | |||||
| sizeof(*singularity_edges), | |||||
| "singularity_edges in solidify"); | |||||
| } | |||||
| singularity_edges[totsingularity][0] = v1; | |||||
| singularity_edges[totsingularity][1] = v2; | |||||
| totsingularity++; | |||||
| if (sctx->edge_adj_polys_len[i] == 1 && sctx->do_rim) { | |||||
| result->numLoops -= 2; | |||||
| result->numPolys--; | |||||
| } | |||||
| } | |||||
| else { | |||||
| result->numEdges--; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| MEM_freeN(face_sides_arr); | |||||
| MEM_freeN(poly_nors); | |||||
| } | } | ||||
| sctx->singularity_edges = singularity_edges; | |||||
| sctx->totsingularity = totsingularity; | |||||
| #undef MOD_SOLIDIFY_EMPTY_TAG | /* Create mesh with proper capacity. */ | ||||
| result->mesh = BKE_mesh_new_nomain_from_template(mesh, | |||||
| (int)(result->numVerts), | |||||
| (int)(result->numEdges), | |||||
| 0, | |||||
| (int)(result->numLoops), | |||||
| (int)(result->numPolys)); | |||||
| return result; | /* Create the final mesh data using the internal SolidifyMesh data. */ | ||||
| solidify_create_final_mesh(sctx); | |||||
| /* Free remaining memory */ | |||||
| solidify_free_context(sctx); | |||||
| return result->mesh; | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| #undef MOD_SOLIDIFY_EMPTY_TAG | |||||
| Context not available. | |||||