Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/mesh_evaluate.cc
| Show All 34 Lines | |||||
| using blender::Span; | using blender::Span; | ||||
| using blender::VArray; | using blender::VArray; | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Polygon Calculations | /** \name Polygon Calculations | ||||
| * \{ */ | * \{ */ | ||||
| static void mesh_calc_ngon_center(const MPoly *mpoly, | static void mesh_calc_ngon_center(const MPoly *mpoly, | ||||
| const MLoop *loopstart, | const int *poly_verts, | ||||
| const float (*positions)[3], | const float (*positions)[3], | ||||
| float cent[3]) | float cent[3]) | ||||
| { | { | ||||
| const float w = 1.0f / float(mpoly->totloop); | const float w = 1.0f / float(mpoly->totloop); | ||||
| zero_v3(cent); | zero_v3(cent); | ||||
| for (int i = 0; i < mpoly->totloop; i++) { | for (int i = 0; i < mpoly->totloop; i++) { | ||||
| madd_v3_v3fl(cent, positions[(loopstart++)->v], w); | madd_v3_v3fl(cent, positions[*(poly_verts++)], w); | ||||
| } | } | ||||
| } | } | ||||
| void BKE_mesh_calc_poly_center(const MPoly *mpoly, | void BKE_mesh_calc_poly_center(const MPoly *mpoly, | ||||
| const MLoop *loopstart, | const int *poly_verts, | ||||
| const float (*vert_positions)[3], | const float (*vert_positions)[3], | ||||
| float r_cent[3]) | float r_cent[3]) | ||||
| { | { | ||||
| if (mpoly->totloop == 3) { | if (mpoly->totloop == 3) { | ||||
| mid_v3_v3v3v3(r_cent, | mid_v3_v3v3v3(r_cent, | ||||
| vert_positions[loopstart[0].v], | vert_positions[poly_verts[0]], | ||||
| vert_positions[loopstart[1].v], | vert_positions[poly_verts[1]], | ||||
| vert_positions[loopstart[2].v]); | vert_positions[poly_verts[2]]); | ||||
| } | } | ||||
| else if (mpoly->totloop == 4) { | else if (mpoly->totloop == 4) { | ||||
| mid_v3_v3v3v3v3(r_cent, | mid_v3_v3v3v3v3(r_cent, | ||||
| vert_positions[loopstart[0].v], | vert_positions[poly_verts[0]], | ||||
| vert_positions[loopstart[1].v], | vert_positions[poly_verts[1]], | ||||
| vert_positions[loopstart[2].v], | vert_positions[poly_verts[2]], | ||||
| vert_positions[loopstart[3].v]); | vert_positions[poly_verts[3]]); | ||||
| } | } | ||||
| else { | else { | ||||
| mesh_calc_ngon_center(mpoly, loopstart, vert_positions, r_cent); | mesh_calc_ngon_center(mpoly, poly_verts, vert_positions, r_cent); | ||||
| } | } | ||||
| } | } | ||||
| float BKE_mesh_calc_poly_area(const MPoly *mpoly, | float BKE_mesh_calc_poly_area(const MPoly *mpoly, | ||||
| const MLoop *loopstart, | const int *poly_verts, | ||||
| const float (*vert_positions)[3]) | const float (*vert_positions)[3]) | ||||
| { | { | ||||
| if (mpoly->totloop == 3) { | if (mpoly->totloop == 3) { | ||||
| return area_tri_v3(vert_positions[loopstart[0].v], | return area_tri_v3(vert_positions[poly_verts[0]], | ||||
| vert_positions[loopstart[1].v], | vert_positions[poly_verts[1]], | ||||
| vert_positions[loopstart[2].v]); | vert_positions[poly_verts[2]]); | ||||
| } | } | ||||
| const MLoop *l_iter = loopstart; | |||||
| float(*vertexcos)[3] = (float(*)[3])BLI_array_alloca(vertexcos, size_t(mpoly->totloop)); | float(*vertexcos)[3] = (float(*)[3])BLI_array_alloca(vertexcos, size_t(mpoly->totloop)); | ||||
| /* pack vertex cos into an array for area_poly_v3 */ | /* pack vertex cos into an array for area_poly_v3 */ | ||||
| for (int i = 0; i < mpoly->totloop; i++, l_iter++) { | for (int i = 0; i < mpoly->totloop; i++) { | ||||
| copy_v3_v3(vertexcos[i], vert_positions[l_iter->v]); | copy_v3_v3(vertexcos[i], vert_positions[poly_verts[i]]); | ||||
| } | } | ||||
| /* finally calculate the area */ | /* finally calculate the area */ | ||||
| float area = area_poly_v3((const float(*)[3])vertexcos, uint(mpoly->totloop)); | float area = area_poly_v3((const float(*)[3])vertexcos, uint(mpoly->totloop)); | ||||
| return area; | return area; | ||||
| } | } | ||||
| float BKE_mesh_calc_area(const Mesh *me) | float BKE_mesh_calc_area(const Mesh *me) | ||||
| { | { | ||||
| const Span<float3> positions = me->vert_positions(); | const Span<float3> positions = me->vert_positions(); | ||||
| const Span<MPoly> polys = me->polys(); | const Span<MPoly> polys = me->polys(); | ||||
| const Span<MLoop> loops = me->loops(); | const Span<int> corner_verts = me->corner_verts(); | ||||
| float total_area = 0.0f; | float total_area = 0.0f; | ||||
| for (const MPoly &poly : polys) { | for (const MPoly &poly : polys) { | ||||
| total_area += BKE_mesh_calc_poly_area( | total_area += BKE_mesh_calc_poly_area(&poly, | ||||
| &poly, &loops[poly.loopstart], reinterpret_cast<const float(*)[3]>(positions.data())); | &corner_verts[poly.loopstart], | ||||
| reinterpret_cast<const float(*)[3]>(positions.data())); | |||||
| } | } | ||||
| return total_area; | return total_area; | ||||
| } | } | ||||
| static float UNUSED_FUNCTION(mesh_calc_poly_volume_centroid)(const MPoly *mpoly, | static float UNUSED_FUNCTION(mesh_calc_poly_volume_centroid)(const MPoly *mpoly, | ||||
| const MLoop *loopstart, | const int *corner_verts, | ||||
| const float (*positions)[3], | const float (*positions)[3], | ||||
| float r_cent[3]) | float r_cent[3]) | ||||
| { | { | ||||
| const float *v_pivot, *v_step1; | const float *v_pivot, *v_step1; | ||||
| float total_volume = 0.0f; | float total_volume = 0.0f; | ||||
| zero_v3(r_cent); | zero_v3(r_cent); | ||||
| v_pivot = positions[loopstart[0].v]; | v_pivot = positions[corner_verts[0]]; | ||||
| v_step1 = positions[loopstart[1].v]; | v_step1 = positions[corner_verts[1]]; | ||||
| for (int i = 2; i < mpoly->totloop; i++) { | for (int i = 2; i < mpoly->totloop; i++) { | ||||
| const float *v_step2 = positions[loopstart[i].v]; | const float *v_step2 = positions[corner_verts[i]]; | ||||
| /* Calculate the 6x volume of the tetrahedron formed by the 3 vertices | /* Calculate the 6x volume of the tetrahedron formed by the 3 vertices | ||||
| * of the triangle and the origin as the fourth vertex */ | * of the triangle and the origin as the fourth vertex */ | ||||
| const float tetra_volume = volume_tri_tetrahedron_signed_v3_6x(v_pivot, v_step1, v_step2); | const float tetra_volume = volume_tri_tetrahedron_signed_v3_6x(v_pivot, v_step1, v_step2); | ||||
| total_volume += tetra_volume; | total_volume += tetra_volume; | ||||
| /* Calculate the centroid of the tetrahedron formed by the 3 vertices | /* Calculate the centroid of the tetrahedron formed by the 3 vertices | ||||
| * of the triangle and the origin as the fourth vertex. | * of the triangle and the origin as the fourth vertex. | ||||
| Show All 12 Lines | |||||
| } | } | ||||
| /** | /** | ||||
| * A version of mesh_calc_poly_volume_centroid that takes an initial reference center, | * A version of mesh_calc_poly_volume_centroid that takes an initial reference center, | ||||
| * use this to increase numeric stability as the quality of the result becomes | * use this to increase numeric stability as the quality of the result becomes | ||||
| * very low quality as the value moves away from 0.0, see: T65986. | * very low quality as the value moves away from 0.0, see: T65986. | ||||
| */ | */ | ||||
| static float mesh_calc_poly_volume_centroid_with_reference_center(const MPoly *mpoly, | static float mesh_calc_poly_volume_centroid_with_reference_center(const MPoly *mpoly, | ||||
| const MLoop *loopstart, | const int *corner_verts, | ||||
| const Span<float3> positions, | const Span<float3> positions, | ||||
| const float reference_center[3], | const float reference_center[3], | ||||
| float r_cent[3]) | float r_cent[3]) | ||||
| { | { | ||||
| /* See: mesh_calc_poly_volume_centroid for comments. */ | /* See: mesh_calc_poly_volume_centroid for comments. */ | ||||
| float v_pivot[3], v_step1[3]; | float v_pivot[3], v_step1[3]; | ||||
| float total_volume = 0.0f; | float total_volume = 0.0f; | ||||
| zero_v3(r_cent); | zero_v3(r_cent); | ||||
| sub_v3_v3v3(v_pivot, positions[loopstart[0].v], reference_center); | sub_v3_v3v3(v_pivot, positions[corner_verts[0]], reference_center); | ||||
| sub_v3_v3v3(v_step1, positions[loopstart[1].v], reference_center); | sub_v3_v3v3(v_step1, positions[corner_verts[1]], reference_center); | ||||
| for (int i = 2; i < mpoly->totloop; i++) { | for (int i = 2; i < mpoly->totloop; i++) { | ||||
| float v_step2[3]; | float v_step2[3]; | ||||
| sub_v3_v3v3(v_step2, positions[loopstart[i].v], reference_center); | sub_v3_v3v3(v_step2, positions[corner_verts[i]], reference_center); | ||||
| const float tetra_volume = volume_tri_tetrahedron_signed_v3_6x(v_pivot, v_step1, v_step2); | const float tetra_volume = volume_tri_tetrahedron_signed_v3_6x(v_pivot, v_step1, v_step2); | ||||
| total_volume += tetra_volume; | total_volume += tetra_volume; | ||||
| for (uint j = 0; j < 3; j++) { | for (uint j = 0; j < 3; j++) { | ||||
| r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]); | r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]); | ||||
| } | } | ||||
| copy_v3_v3(v_step1, v_step2); | copy_v3_v3(v_step1, v_step2); | ||||
| } | } | ||||
| return total_volume; | return total_volume; | ||||
| } | } | ||||
| /** | /** | ||||
| * \note | * \note | ||||
| * - Results won't be correct if polygon is non-planar. | * - Results won't be correct if polygon is non-planar. | ||||
| * - This has the advantage over #mesh_calc_poly_volume_centroid | * - This has the advantage over #mesh_calc_poly_volume_centroid | ||||
| * that it doesn't depend on solid geometry, instead it weights the surface by volume. | * that it doesn't depend on solid geometry, instead it weights the surface by volume. | ||||
| */ | */ | ||||
| static float mesh_calc_poly_area_centroid(const MPoly *mpoly, | static float mesh_calc_poly_area_centroid(const MPoly *mpoly, | ||||
| const MLoop *loopstart, | const int *poly_verts, | ||||
| const float (*positions)[3], | const float (*positions)[3], | ||||
| float r_cent[3]) | float r_cent[3]) | ||||
| { | { | ||||
| float total_area = 0.0f; | float total_area = 0.0f; | ||||
| float v1[3], v2[3], v3[3], normal[3], tri_cent[3]; | float v1[3], v2[3], v3[3], normal[3], tri_cent[3]; | ||||
| BKE_mesh_calc_poly_normal(mpoly, loopstart, positions, normal); | BKE_mesh_calc_poly_normal(mpoly, poly_verts, positions, normal); | ||||
| copy_v3_v3(v1, positions[loopstart[0].v]); | copy_v3_v3(v1, positions[poly_verts[0]]); | ||||
| copy_v3_v3(v2, positions[loopstart[1].v]); | copy_v3_v3(v2, positions[poly_verts[1]]); | ||||
| zero_v3(r_cent); | zero_v3(r_cent); | ||||
| for (int i = 2; i < mpoly->totloop; i++) { | for (int i = 2; i < mpoly->totloop; i++) { | ||||
| copy_v3_v3(v3, positions[loopstart[i].v]); | copy_v3_v3(v3, positions[poly_verts[i]]); | ||||
| float tri_area = area_tri_signed_v3(v1, v2, v3, normal); | float tri_area = area_tri_signed_v3(v1, v2, v3, normal); | ||||
| total_area += tri_area; | total_area += tri_area; | ||||
| mid_v3_v3v3v3(tri_cent, v1, v2, v3); | mid_v3_v3v3v3(tri_cent, v1, v2, v3); | ||||
| madd_v3_v3fl(r_cent, tri_cent, tri_area); | madd_v3_v3fl(r_cent, tri_cent, tri_area); | ||||
| copy_v3_v3(v2, v3); | copy_v3_v3(v2, v3); | ||||
| } | } | ||||
| mul_v3_fl(r_cent, 1.0f / total_area); | mul_v3_fl(r_cent, 1.0f / total_area); | ||||
| return total_area; | return total_area; | ||||
| } | } | ||||
| void BKE_mesh_calc_poly_angles(const MPoly *mpoly, | void BKE_mesh_calc_poly_angles(const MPoly *mpoly, | ||||
| const MLoop *loopstart, | const int *poly_verts, | ||||
| const float (*vert_positions)[3], | const float (*vert_positions)[3], | ||||
| float angles[]) | float angles[]) | ||||
| { | { | ||||
| float nor_prev[3]; | float nor_prev[3]; | ||||
| float nor_next[3]; | float nor_next[3]; | ||||
| int i_this = mpoly->totloop - 1; | int i_this = mpoly->totloop - 1; | ||||
| int i_next = 0; | int i_next = 0; | ||||
| sub_v3_v3v3( | sub_v3_v3v3( | ||||
| nor_prev, vert_positions[loopstart[i_this - 1].v], vert_positions[loopstart[i_this].v]); | nor_prev, vert_positions[poly_verts[i_this - 1]], vert_positions[poly_verts[i_this]]); | ||||
| normalize_v3(nor_prev); | normalize_v3(nor_prev); | ||||
| while (i_next < mpoly->totloop) { | while (i_next < mpoly->totloop) { | ||||
| sub_v3_v3v3( | sub_v3_v3v3(nor_next, vert_positions[poly_verts[i_this]], vert_positions[poly_verts[i_next]]); | ||||
| nor_next, vert_positions[loopstart[i_this].v], vert_positions[loopstart[i_next].v]); | |||||
| normalize_v3(nor_next); | normalize_v3(nor_next); | ||||
| angles[i_this] = angle_normalized_v3v3(nor_prev, nor_next); | angles[i_this] = angle_normalized_v3v3(nor_prev, nor_next); | ||||
| /* step */ | /* step */ | ||||
| copy_v3_v3(nor_prev, nor_next); | copy_v3_v3(nor_prev, nor_next); | ||||
| i_this = i_next; | i_this = i_next; | ||||
| i_next++; | i_next++; | ||||
| } | } | ||||
| } | } | ||||
| void BKE_mesh_poly_edgehash_insert(EdgeHash *ehash, const MPoly *mp, const MLoop *mloop) | void BKE_mesh_poly_edgehash_insert(EdgeHash *ehash, const MPoly *mp, const int *corner_verts) | ||||
| { | { | ||||
| const MLoop *ml, *ml_next; | |||||
| int i = mp->totloop; | int i = mp->totloop; | ||||
| ml_next = mloop; /* first loop */ | int corner_next = mp->loopstart; /* first loop */ | ||||
| ml = &ml_next[i - 1]; /* last loop */ | int corner = corner_next + (i - 1); /* last loop */ | ||||
| while (i-- != 0) { | while (i-- != 0) { | ||||
| BLI_edgehash_reinsert(ehash, ml->v, ml_next->v, nullptr); | BLI_edgehash_reinsert(ehash, corner_verts[corner], corner_verts[corner_next], nullptr); | ||||
| ml = ml_next; | corner = corner_next; | ||||
| ml_next++; | corner_next++; | ||||
| } | } | ||||
| } | } | ||||
| void BKE_mesh_poly_edgebitmap_insert(uint *edge_bitmap, const MPoly *mp, const MLoop *mloop) | void BKE_mesh_poly_edgebitmap_insert(uint *edge_bitmap, const MPoly *mp, const int *poly_edges) | ||||
| { | { | ||||
| const MLoop *ml; | using namespace blender; | ||||
| int i = mp->totloop; | for (const int i : IndexRange(mp->totloop)) { | ||||
| BLI_BITMAP_ENABLE(edge_bitmap, poly_edges[i]); | |||||
| ml = mloop; | |||||
| while (i-- != 0) { | |||||
| BLI_BITMAP_ENABLE(edge_bitmap, ml->e); | |||||
| ml++; | |||||
| } | } | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Mesh Center Calculation | /** \name Mesh Center Calculation | ||||
| * \{ */ | * \{ */ | ||||
| Show All 12 Lines | bool BKE_mesh_center_median(const Mesh *me, float r_cent[3]) | ||||
| return (me->totvert != 0); | return (me->totvert != 0); | ||||
| } | } | ||||
| bool BKE_mesh_center_median_from_polys(const Mesh *me, float r_cent[3]) | bool BKE_mesh_center_median_from_polys(const Mesh *me, float r_cent[3]) | ||||
| { | { | ||||
| int tot = 0; | int tot = 0; | ||||
| const Span<float3> positions = me->vert_positions(); | const Span<float3> positions = me->vert_positions(); | ||||
| const Span<MPoly> polys = me->polys(); | const Span<MPoly> polys = me->polys(); | ||||
| const Span<MLoop> loops = me->loops(); | const Span<int> corner_verts = me->corner_verts(); | ||||
| zero_v3(r_cent); | zero_v3(r_cent); | ||||
| for (const MPoly &poly : polys) { | for (const MPoly &poly : polys) { | ||||
| int loopend = poly.loopstart + poly.totloop; | int loopend = poly.loopstart + poly.totloop; | ||||
| for (int j = poly.loopstart; j < loopend; j++) { | for (int j = poly.loopstart; j < loopend; j++) { | ||||
| add_v3_v3(r_cent, positions[loops[j].v]); | add_v3_v3(r_cent, positions[corner_verts[j]]); | ||||
| } | } | ||||
| tot += poly.totloop; | tot += poly.totloop; | ||||
| } | } | ||||
| /* otherwise we get NAN for 0 verts */ | /* otherwise we get NAN for 0 verts */ | ||||
| if (me->totpoly) { | if (me->totpoly) { | ||||
| mul_v3_fl(r_cent, 1.0f / float(tot)); | mul_v3_fl(r_cent, 1.0f / float(tot)); | ||||
| } | } | ||||
| return (me->totpoly != 0); | return (me->totpoly != 0); | ||||
| Show All 15 Lines | |||||
| { | { | ||||
| int i = me->totpoly; | int i = me->totpoly; | ||||
| const MPoly *mpoly; | const MPoly *mpoly; | ||||
| float poly_area; | float poly_area; | ||||
| float total_area = 0.0f; | float total_area = 0.0f; | ||||
| float poly_cent[3]; | float poly_cent[3]; | ||||
| const float(*positions)[3] = BKE_mesh_vert_positions(me); | const float(*positions)[3] = BKE_mesh_vert_positions(me); | ||||
| const MPoly *polys = BKE_mesh_polys(me); | const MPoly *polys = BKE_mesh_polys(me); | ||||
| const MLoop *loops = BKE_mesh_loops(me); | const Span<int> corner_verts = me->corner_verts(); | ||||
| zero_v3(r_cent); | zero_v3(r_cent); | ||||
| /* calculate a weighted average of polygon centroids */ | /* calculate a weighted average of polygon centroids */ | ||||
| for (mpoly = polys; i--; mpoly++) { | for (mpoly = polys; i--; mpoly++) { | ||||
| poly_area = mesh_calc_poly_area_centroid( | poly_area = mesh_calc_poly_area_centroid( | ||||
| mpoly, loops + mpoly->loopstart, positions, poly_cent); | mpoly, &corner_verts[mpoly->loopstart], positions, poly_cent); | ||||
| madd_v3_v3fl(r_cent, poly_cent, poly_area); | madd_v3_v3fl(r_cent, poly_cent, poly_area); | ||||
| total_area += poly_area; | total_area += poly_area; | ||||
| } | } | ||||
| /* otherwise we get NAN for 0 polys */ | /* otherwise we get NAN for 0 polys */ | ||||
| if (me->totpoly) { | if (me->totpoly) { | ||||
| mul_v3_fl(r_cent, 1.0f / total_area); | mul_v3_fl(r_cent, 1.0f / total_area); | ||||
| } | } | ||||
| Show All 10 Lines | |||||
| { | { | ||||
| int i = me->totpoly; | int i = me->totpoly; | ||||
| const MPoly *mpoly; | const MPoly *mpoly; | ||||
| float poly_volume; | float poly_volume; | ||||
| float total_volume = 0.0f; | float total_volume = 0.0f; | ||||
| float poly_cent[3]; | float poly_cent[3]; | ||||
| const Span<float3> positions = me->vert_positions(); | const Span<float3> positions = me->vert_positions(); | ||||
| const MPoly *polys = BKE_mesh_polys(me); | const MPoly *polys = BKE_mesh_polys(me); | ||||
| const MLoop *loops = BKE_mesh_loops(me); | const Span<int> corner_verts = me->corner_verts(); | ||||
| /* Use an initial center to avoid numeric instability of geometry far away from the center. */ | /* Use an initial center to avoid numeric instability of geometry far away from the center. */ | ||||
| float init_cent[3]; | float init_cent[3]; | ||||
| const bool init_cent_result = BKE_mesh_center_median_from_polys(me, init_cent); | const bool init_cent_result = BKE_mesh_center_median_from_polys(me, init_cent); | ||||
| zero_v3(r_cent); | zero_v3(r_cent); | ||||
| /* calculate a weighted average of polyhedron centroids */ | /* calculate a weighted average of polyhedron centroids */ | ||||
| for (mpoly = polys; i--; mpoly++) { | for (mpoly = polys; i--; mpoly++) { | ||||
| poly_volume = mesh_calc_poly_volume_centroid_with_reference_center( | poly_volume = mesh_calc_poly_volume_centroid_with_reference_center( | ||||
| mpoly, loops + mpoly->loopstart, positions, init_cent, poly_cent); | mpoly, &corner_verts[mpoly->loopstart], positions, init_cent, poly_cent); | ||||
| /* poly_cent is already volume-weighted, so no need to multiply by the volume */ | /* poly_cent is already volume-weighted, so no need to multiply by the volume */ | ||||
| add_v3_v3(r_cent, poly_cent); | add_v3_v3(r_cent, poly_cent); | ||||
| total_volume += poly_volume; | total_volume += poly_volume; | ||||
| } | } | ||||
| /* otherwise we get NAN for 0 polys */ | /* otherwise we get NAN for 0 polys */ | ||||
| if (total_volume != 0.0f) { | if (total_volume != 0.0f) { | ||||
| /* multiply by 0.25 to get the correct centroid */ | /* multiply by 0.25 to get the correct centroid */ | ||||
| Show All 16 Lines | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Mesh Volume Calculation | /** \name Mesh Volume Calculation | ||||
| * \{ */ | * \{ */ | ||||
| static bool mesh_calc_center_centroid_ex(const float (*positions)[3], | static bool mesh_calc_center_centroid_ex(const float (*positions)[3], | ||||
| int /*mverts_num*/, | int /*mverts_num*/, | ||||
| const MLoopTri *looptri, | const MLoopTri *looptri, | ||||
| int looptri_num, | int looptri_num, | ||||
| const MLoop *mloop, | const int *corner_verts, | ||||
| float r_center[3]) | float r_center[3]) | ||||
| { | { | ||||
| zero_v3(r_center); | zero_v3(r_center); | ||||
| if (looptri_num == 0) { | if (looptri_num == 0) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| float totweight = 0.0f; | float totweight = 0.0f; | ||||
| const MLoopTri *lt; | const MLoopTri *lt; | ||||
| int i; | int i; | ||||
| for (i = 0, lt = looptri; i < looptri_num; i++, lt++) { | for (i = 0, lt = looptri; i < looptri_num; i++, lt++) { | ||||
| const float *v1 = positions[mloop[lt->tri[0]].v]; | const float *v1 = positions[corner_verts[lt->tri[0]]]; | ||||
| const float *v2 = positions[mloop[lt->tri[1]].v]; | const float *v2 = positions[corner_verts[lt->tri[1]]]; | ||||
| const float *v3 = positions[mloop[lt->tri[2]].v]; | const float *v3 = positions[corner_verts[lt->tri[2]]]; | ||||
| float area; | float area; | ||||
| area = area_tri_v3(v1, v2, v3); | area = area_tri_v3(v1, v2, v3); | ||||
| madd_v3_v3fl(r_center, v1, area); | madd_v3_v3fl(r_center, v1, area); | ||||
| madd_v3_v3fl(r_center, v2, area); | madd_v3_v3fl(r_center, v2, area); | ||||
| madd_v3_v3fl(r_center, v3, area); | madd_v3_v3fl(r_center, v3, area); | ||||
| totweight += area; | totweight += area; | ||||
| } | } | ||||
| if (totweight == 0.0f) { | if (totweight == 0.0f) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| mul_v3_fl(r_center, 1.0f / (3.0f * totweight)); | mul_v3_fl(r_center, 1.0f / (3.0f * totweight)); | ||||
| return true; | return true; | ||||
| } | } | ||||
| void BKE_mesh_calc_volume(const float (*vert_positions)[3], | void BKE_mesh_calc_volume(const float (*vert_positions)[3], | ||||
| const int mverts_num, | const int mverts_num, | ||||
| const MLoopTri *looptri, | const MLoopTri *looptri, | ||||
| const int looptri_num, | const int looptri_num, | ||||
| const MLoop *mloop, | const int *corner_verts, | ||||
| float *r_volume, | float *r_volume, | ||||
| float r_center[3]) | float r_center[3]) | ||||
| { | { | ||||
| const MLoopTri *lt; | const MLoopTri *lt; | ||||
| float center[3]; | float center[3]; | ||||
| float totvol; | float totvol; | ||||
| int i; | int i; | ||||
| if (r_volume) { | if (r_volume) { | ||||
| *r_volume = 0.0f; | *r_volume = 0.0f; | ||||
| } | } | ||||
| if (r_center) { | if (r_center) { | ||||
| zero_v3(r_center); | zero_v3(r_center); | ||||
| } | } | ||||
| if (looptri_num == 0) { | if (looptri_num == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (!mesh_calc_center_centroid_ex( | if (!mesh_calc_center_centroid_ex( | ||||
| vert_positions, mverts_num, looptri, looptri_num, mloop, center)) { | vert_positions, mverts_num, looptri, looptri_num, corner_verts, center)) { | ||||
| return; | return; | ||||
| } | } | ||||
| totvol = 0.0f; | totvol = 0.0f; | ||||
| for (i = 0, lt = looptri; i < looptri_num; i++, lt++) { | for (i = 0, lt = looptri; i < looptri_num; i++, lt++) { | ||||
| const float *v1 = vert_positions[mloop[lt->tri[0]].v]; | const float *v1 = vert_positions[corner_verts[lt->tri[0]]]; | ||||
| const float *v2 = vert_positions[mloop[lt->tri[1]].v]; | const float *v2 = vert_positions[corner_verts[lt->tri[1]]]; | ||||
| const float *v3 = vert_positions[mloop[lt->tri[2]].v]; | const float *v3 = vert_positions[corner_verts[lt->tri[2]]]; | ||||
| float vol; | float vol; | ||||
| vol = volume_tetrahedron_signed_v3(center, v1, v2, v3); | vol = volume_tetrahedron_signed_v3(center, v1, v2, v3); | ||||
| if (r_volume) { | if (r_volume) { | ||||
| totvol += vol; | totvol += vol; | ||||
| } | } | ||||
| if (r_center) { | if (r_center) { | ||||
| /* averaging factor 1/3 is applied in the end */ | /* averaging factor 1/3 is applied in the end */ | ||||
| ▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | for (int x = 0; x < sides; x++) { | ||||
| if (use_loop_mdisp_flip) { | if (use_loop_mdisp_flip) { | ||||
| co_a[2] *= -1.0f; | co_a[2] *= -1.0f; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void BKE_mesh_polygon_flip_ex(const MPoly *mpoly, | void BKE_mesh_polygon_flip_ex(const MPoly *mpoly, | ||||
| MLoop *mloop, | int *corner_verts, | ||||
| int *corner_edges, | |||||
| CustomData *ldata, | CustomData *ldata, | ||||
| float (*lnors)[3], | float (*lnors)[3], | ||||
| MDisps *mdisp, | MDisps *mdisp, | ||||
| const bool use_loop_mdisp_flip) | const bool use_loop_mdisp_flip) | ||||
| { | { | ||||
| int loopstart = mpoly->loopstart; | int loopstart = mpoly->loopstart; | ||||
| int loopend = loopstart + mpoly->totloop - 1; | int loopend = loopstart + mpoly->totloop - 1; | ||||
| const bool loops_in_ldata = (CustomData_get_layer(ldata, CD_MLOOP) == mloop); | const bool corner_verts_in_data = (CustomData_get_layer_named( | ||||
| ldata, CD_PROP_INT32, ".corner_vert") == corner_verts); | |||||
| const bool corner_edges_in_data = (CustomData_get_layer_named( | |||||
| ldata, CD_PROP_INT32, ".corner_edge") == corner_edges); | |||||
| if (mdisp) { | if (mdisp) { | ||||
| for (int i = loopstart; i <= loopend; i++) { | for (int i = loopstart; i <= loopend; i++) { | ||||
| BKE_mesh_mdisp_flip(&mdisp[i], use_loop_mdisp_flip); | BKE_mesh_mdisp_flip(&mdisp[i], use_loop_mdisp_flip); | ||||
| } | } | ||||
| } | } | ||||
| /* Note that we keep same start vertex for flipped face. */ | /* Note that we keep same start vertex for flipped face. */ | ||||
| /* We also have to update loops edge | /* We also have to update loops edge | ||||
| * (they will get their original 'other edge', that is, | * (they will get their original 'other edge', that is, | ||||
| * the original edge of their original previous loop)... */ | * the original edge of their original previous loop)... */ | ||||
| uint prev_edge_index = mloop[loopstart].e; | int prev_edge_index = corner_edges[loopstart]; | ||||
| mloop[loopstart].e = mloop[loopend].e; | corner_edges[loopstart] = corner_edges[loopend]; | ||||
| for (loopstart++; loopend > loopstart; loopstart++, loopend--) { | for (loopstart++; loopend > loopstart; loopstart++, loopend--) { | ||||
| mloop[loopend].e = mloop[loopend - 1].e; | corner_edges[loopend] = corner_edges[loopend - 1]; | ||||
| std::swap(mloop[loopstart].e, prev_edge_index); | std::swap(corner_edges[loopstart], prev_edge_index); | ||||
| if (!loops_in_ldata) { | if (!corner_verts_in_data) { | ||||
| std::swap(mloop[loopstart], mloop[loopend]); | std::swap(corner_verts[loopstart], corner_verts[loopend]); | ||||
| } | |||||
| if (!corner_edges_in_data) { | |||||
| std::swap(corner_edges[loopstart], corner_edges[loopend]); | |||||
| } | } | ||||
| if (lnors) { | if (lnors) { | ||||
| swap_v3_v3(lnors[loopstart], lnors[loopend]); | swap_v3_v3(lnors[loopstart], lnors[loopend]); | ||||
| } | } | ||||
| CustomData_swap(ldata, loopstart, loopend); | CustomData_swap(ldata, loopstart, loopend); | ||||
| } | } | ||||
| /* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */ | /* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */ | ||||
| if (loopstart == loopend) { | if (loopstart == loopend) { | ||||
| mloop[loopstart].e = prev_edge_index; | corner_edges[loopstart] = prev_edge_index; | ||||
| } | } | ||||
| } | } | ||||
| void BKE_mesh_polygon_flip(const MPoly *mpoly, MLoop *mloop, CustomData *ldata, const int totloop) | void BKE_mesh_polygon_flip( | ||||
| const MPoly *mpoly, int *corner_verts, int *corner_edges, CustomData *ldata, const int totloop) | |||||
| { | { | ||||
| MDisps *mdisp = (MDisps *)CustomData_get_layer_for_write(ldata, CD_MDISPS, totloop); | MDisps *mdisp = (MDisps *)CustomData_get_layer_for_write(ldata, CD_MDISPS, totloop); | ||||
| BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, nullptr, mdisp, true); | BKE_mesh_polygon_flip_ex(mpoly, corner_verts, corner_edges, ldata, nullptr, mdisp, true); | ||||
| } | } | ||||
| void BKE_mesh_polys_flip(const MPoly *mpoly, MLoop *mloop, CustomData *ldata, int totpoly) | void BKE_mesh_polys_flip( | ||||
| const MPoly *mpoly, int *corner_verts, int *corner_edges, CustomData *ldata, int totpoly) | |||||
| { | { | ||||
| MDisps *mdisp = (MDisps *)CustomData_get_layer_for_write(ldata, CD_MDISPS, totpoly); | MDisps *mdisp = (MDisps *)CustomData_get_layer_for_write(ldata, CD_MDISPS, totpoly); | ||||
| const MPoly *mp; | const MPoly *mp; | ||||
| int i; | int i; | ||||
| for (mp = mpoly, i = 0; i < totpoly; mp++, i++) { | for (mp = mpoly, i = 0; i < totpoly; mp++, i++) { | ||||
| BKE_mesh_polygon_flip_ex(mp, mloop, ldata, nullptr, mdisp, true); | BKE_mesh_polygon_flip_ex(mp, corner_verts, corner_edges, ldata, nullptr, mdisp, true); | ||||
| } | } | ||||
| } | } | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Mesh Flag Flushing | /** \name Mesh Flag Flushing | ||||
| * \{ */ | * \{ */ | ||||
| void BKE_mesh_flush_hidden_from_verts(Mesh *me) | void BKE_mesh_flush_hidden_from_verts(Mesh *me) | ||||
| { | { | ||||
| using namespace blender; | using namespace blender; | ||||
| using namespace blender::bke; | using namespace blender::bke; | ||||
| MutableAttributeAccessor attributes = me->attributes_for_write(); | MutableAttributeAccessor attributes = me->attributes_for_write(); | ||||
| const VArray<bool> hide_vert = attributes.lookup_or_default<bool>( | const VArray<bool> hide_vert = attributes.lookup_or_default<bool>( | ||||
| ".hide_vert", ATTR_DOMAIN_POINT, false); | ".hide_vert", ATTR_DOMAIN_POINT, false); | ||||
| if (hide_vert.is_single() && !hide_vert.get_internal_single()) { | if (hide_vert.is_single() && !hide_vert.get_internal_single()) { | ||||
| attributes.remove(".hide_edge"); | attributes.remove(".hide_edge"); | ||||
| attributes.remove(".hide_poly"); | attributes.remove(".hide_poly"); | ||||
| return; | return; | ||||
| } | } | ||||
| const VArraySpan<bool> hide_vert_span{hide_vert}; | const VArraySpan<bool> hide_vert_span{hide_vert}; | ||||
| const Span<MEdge> edges = me->edges(); | const Span<MEdge> edges = me->edges(); | ||||
| const Span<MPoly> polys = me->polys(); | const Span<MPoly> polys = me->polys(); | ||||
| const Span<MLoop> loops = me->loops(); | const Span<int> corner_verts = me->corner_verts(); | ||||
| /* Hide edges when either of their vertices are hidden. */ | /* Hide edges when either of their vertices are hidden. */ | ||||
| SpanAttributeWriter<bool> hide_edge = attributes.lookup_or_add_for_write_only_span<bool>( | SpanAttributeWriter<bool> hide_edge = attributes.lookup_or_add_for_write_only_span<bool>( | ||||
| ".hide_edge", ATTR_DOMAIN_EDGE); | ".hide_edge", ATTR_DOMAIN_EDGE); | ||||
| for (const int i : edges.index_range()) { | for (const int i : edges.index_range()) { | ||||
| const MEdge &edge = edges[i]; | const MEdge &edge = edges[i]; | ||||
| hide_edge.span[i] = hide_vert_span[edge.v1] || hide_vert_span[edge.v2]; | hide_edge.span[i] = hide_vert_span[edge.v1] || hide_vert_span[edge.v2]; | ||||
| } | } | ||||
| hide_edge.finish(); | hide_edge.finish(); | ||||
| /* Hide polygons when any of their vertices are hidden. */ | /* Hide polygons when any of their vertices are hidden. */ | ||||
| SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>( | SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>( | ||||
| ".hide_poly", ATTR_DOMAIN_FACE); | ".hide_poly", ATTR_DOMAIN_FACE); | ||||
| for (const int i : polys.index_range()) { | for (const int i : polys.index_range()) { | ||||
| const MPoly &poly = polys[i]; | const MPoly &poly = polys[i]; | ||||
| const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop); | const Span<int> poly_verts = corner_verts.slice(poly.loopstart, poly.totloop); | ||||
| hide_poly.span[i] = std::any_of(poly_loops.begin(), poly_loops.end(), [&](const MLoop &loop) { | hide_poly.span[i] = std::any_of(poly_verts.begin(), poly_verts.end(), [&](const int vert_i) { | ||||
| return hide_vert_span[loop.v]; | return hide_vert_span[vert_i]; | ||||
| }); | }); | ||||
| } | } | ||||
| hide_poly.finish(); | hide_poly.finish(); | ||||
| } | } | ||||
| void BKE_mesh_flush_hidden_from_polys(Mesh *me) | void BKE_mesh_flush_hidden_from_polys(Mesh *me) | ||||
| { | { | ||||
| using namespace blender; | using namespace blender; | ||||
| using namespace blender::bke; | using namespace blender::bke; | ||||
| MutableAttributeAccessor attributes = me->attributes_for_write(); | MutableAttributeAccessor attributes = me->attributes_for_write(); | ||||
| const VArray<bool> hide_poly = attributes.lookup_or_default<bool>( | const VArray<bool> hide_poly = attributes.lookup_or_default<bool>( | ||||
| ".hide_poly", ATTR_DOMAIN_FACE, false); | ".hide_poly", ATTR_DOMAIN_FACE, false); | ||||
| if (hide_poly.is_single() && !hide_poly.get_internal_single()) { | if (hide_poly.is_single() && !hide_poly.get_internal_single()) { | ||||
| attributes.remove(".hide_vert"); | attributes.remove(".hide_vert"); | ||||
| attributes.remove(".hide_edge"); | attributes.remove(".hide_edge"); | ||||
| return; | return; | ||||
| } | } | ||||
| const VArraySpan<bool> hide_poly_span{hide_poly}; | const VArraySpan<bool> hide_poly_span{hide_poly}; | ||||
| const Span<MPoly> polys = me->polys(); | const Span<MPoly> polys = me->polys(); | ||||
| const Span<MLoop> loops = me->loops(); | const Span<int> corner_verts = me->corner_verts(); | ||||
| const Span<int> corner_edges = me->corner_edges(); | |||||
| SpanAttributeWriter<bool> hide_vert = attributes.lookup_or_add_for_write_only_span<bool>( | SpanAttributeWriter<bool> hide_vert = attributes.lookup_or_add_for_write_only_span<bool>( | ||||
| ".hide_vert", ATTR_DOMAIN_POINT); | ".hide_vert", ATTR_DOMAIN_POINT); | ||||
| SpanAttributeWriter<bool> hide_edge = attributes.lookup_or_add_for_write_only_span<bool>( | SpanAttributeWriter<bool> hide_edge = attributes.lookup_or_add_for_write_only_span<bool>( | ||||
| ".hide_edge", ATTR_DOMAIN_EDGE); | ".hide_edge", ATTR_DOMAIN_EDGE); | ||||
| /* Hide all edges or vertices connected to hidden polygons. */ | /* Hide all edges or vertices connected to hidden polygons. */ | ||||
| for (const int i : polys.index_range()) { | for (const int i : polys.index_range()) { | ||||
| if (hide_poly_span[i]) { | if (hide_poly_span[i]) { | ||||
| const MPoly &poly = polys[i]; | const MPoly &poly = polys[i]; | ||||
| for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { | for (const int corner : IndexRange(poly.loopstart, poly.totloop)) { | ||||
| hide_vert.span[loop.v] = true; | hide_vert.span[corner_verts[corner]] = true; | ||||
| hide_edge.span[loop.e] = true; | hide_edge.span[corner_edges[corner]] = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Unhide vertices and edges connected to visible polygons. */ | /* Unhide vertices and edges connected to visible polygons. */ | ||||
| for (const int i : polys.index_range()) { | for (const int i : polys.index_range()) { | ||||
| if (!hide_poly_span[i]) { | if (!hide_poly_span[i]) { | ||||
| const MPoly &poly = polys[i]; | const MPoly &poly = polys[i]; | ||||
| for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { | for (const int corner : IndexRange(poly.loopstart, poly.totloop)) { | ||||
| hide_vert.span[loop.v] = false; | hide_vert.span[corner_verts[corner]] = false; | ||||
| hide_edge.span[loop.e] = false; | hide_edge.span[corner_edges[corner]] = false; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| hide_vert.finish(); | hide_vert.finish(); | ||||
| hide_edge.finish(); | hide_edge.finish(); | ||||
| } | } | ||||
| Show All 21 Lines | attributes.lookup_or_default<bool>(".select_poly", ATTR_DOMAIN_EDGE, false) | ||||
| .materialize(select_edge.span); | .materialize(select_edge.span); | ||||
| select_vert.finish(); | select_vert.finish(); | ||||
| select_edge.finish(); | select_edge.finish(); | ||||
| } | } | ||||
| static void mesh_flush_select_from_verts(const Span<MEdge> edges, | static void mesh_flush_select_from_verts(const Span<MEdge> edges, | ||||
| const Span<MPoly> polys, | const Span<MPoly> polys, | ||||
| const Span<MLoop> loops, | const Span<int> corner_verts, | ||||
| const VArray<bool> &hide_edge, | const VArray<bool> &hide_edge, | ||||
| const VArray<bool> &hide_poly, | const VArray<bool> &hide_poly, | ||||
| const VArray<bool> &select_vert, | const VArray<bool> &select_vert, | ||||
| MutableSpan<bool> select_edge, | MutableSpan<bool> select_edge, | ||||
| MutableSpan<bool> select_poly) | MutableSpan<bool> select_poly) | ||||
| { | { | ||||
| /* Select visible edges that have both of their vertices selected. */ | /* Select visible edges that have both of their vertices selected. */ | ||||
| for (const int i : edges.index_range()) { | for (const int i : edges.index_range()) { | ||||
| if (!hide_edge[i]) { | if (!hide_edge[i]) { | ||||
| const MEdge &edge = edges[i]; | const MEdge &edge = edges[i]; | ||||
| select_edge[i] = select_vert[edge.v1] && select_vert[edge.v2]; | select_edge[i] = select_vert[edge.v1] && select_vert[edge.v2]; | ||||
| } | } | ||||
| } | } | ||||
| /* Select visible faces that have all of their vertices selected. */ | /* Select visible faces that have all of their vertices selected. */ | ||||
| for (const int i : polys.index_range()) { | for (const int i : polys.index_range()) { | ||||
| if (!hide_poly[i]) { | if (!hide_poly[i]) { | ||||
| const MPoly &poly = polys[i]; | const MPoly &poly = polys[i]; | ||||
| const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop); | const Span<int> poly_verts = corner_verts.slice(poly.loopstart, poly.totloop); | ||||
| select_poly[i] = std::all_of(poly_loops.begin(), poly_loops.end(), [&](const MLoop &loop) { | select_poly[i] = std::all_of(poly_verts.begin(), poly_verts.end(), [&](const int vert_i) { | ||||
| return select_vert[loop.v]; | return select_vert[vert_i]; | ||||
| }); | }); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void BKE_mesh_flush_select_from_verts(Mesh *me) | void BKE_mesh_flush_select_from_verts(Mesh *me) | ||||
| { | { | ||||
| using namespace blender::bke; | using namespace blender::bke; | ||||
| MutableAttributeAccessor attributes = me->attributes_for_write(); | MutableAttributeAccessor attributes = me->attributes_for_write(); | ||||
| const VArray<bool> select_vert = attributes.lookup_or_default<bool>( | const VArray<bool> select_vert = attributes.lookup_or_default<bool>( | ||||
| ".select_vert", ATTR_DOMAIN_POINT, false); | ".select_vert", ATTR_DOMAIN_POINT, false); | ||||
| if (select_vert.is_single() && !select_vert.get_internal_single()) { | if (select_vert.is_single() && !select_vert.get_internal_single()) { | ||||
| attributes.remove(".select_edge"); | attributes.remove(".select_edge"); | ||||
| attributes.remove(".select_poly"); | attributes.remove(".select_poly"); | ||||
| return; | return; | ||||
| } | } | ||||
| SpanAttributeWriter<bool> select_edge = attributes.lookup_or_add_for_write_only_span<bool>( | SpanAttributeWriter<bool> select_edge = attributes.lookup_or_add_for_write_only_span<bool>( | ||||
| ".select_edge", ATTR_DOMAIN_EDGE); | ".select_edge", ATTR_DOMAIN_EDGE); | ||||
| SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_only_span<bool>( | SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_only_span<bool>( | ||||
| ".select_poly", ATTR_DOMAIN_FACE); | ".select_poly", ATTR_DOMAIN_FACE); | ||||
| mesh_flush_select_from_verts( | mesh_flush_select_from_verts( | ||||
| me->edges(), | me->edges(), | ||||
| me->polys(), | me->polys(), | ||||
| me->loops(), | me->corner_verts(), | ||||
| attributes.lookup_or_default<bool>(".hide_edge", ATTR_DOMAIN_EDGE, false), | attributes.lookup_or_default<bool>(".hide_edge", ATTR_DOMAIN_EDGE, false), | ||||
| attributes.lookup_or_default<bool>(".hide_poly", ATTR_DOMAIN_FACE, false), | attributes.lookup_or_default<bool>(".hide_poly", ATTR_DOMAIN_FACE, false), | ||||
| select_vert, | select_vert, | ||||
| select_edge.span, | select_edge.span, | ||||
| select_poly.span); | select_poly.span); | ||||
| select_edge.finish(); | select_edge.finish(); | ||||
| select_poly.finish(); | select_poly.finish(); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Mesh Spatial Calculation | /** \name Mesh Spatial Calculation | ||||
| * \{ */ | * \{ */ | ||||
| void BKE_mesh_calc_relative_deform(const MPoly *mpoly, | void BKE_mesh_calc_relative_deform(const MPoly *mpoly, | ||||
| const int totpoly, | const int totpoly, | ||||
| const MLoop *mloop, | const int *corner_verts, | ||||
| const int totvert, | const int totvert, | ||||
| const float (*vert_cos_src)[3], | const float (*vert_cos_src)[3], | ||||
| const float (*vert_cos_dst)[3], | const float (*vert_cos_dst)[3], | ||||
| const float (*vert_cos_org)[3], | const float (*vert_cos_org)[3], | ||||
| float (*vert_cos_new)[3]) | float (*vert_cos_new)[3]) | ||||
| { | { | ||||
| const MPoly *mp; | const MPoly *mp; | ||||
| int i; | int i; | ||||
| int *vert_accum = (int *)MEM_calloc_arrayN(size_t(totvert), sizeof(*vert_accum), __func__); | int *vert_accum = (int *)MEM_calloc_arrayN(size_t(totvert), sizeof(*vert_accum), __func__); | ||||
| memset(vert_cos_new, '\0', sizeof(*vert_cos_new) * size_t(totvert)); | memset(vert_cos_new, '\0', sizeof(*vert_cos_new) * size_t(totvert)); | ||||
| for (i = 0, mp = mpoly; i < totpoly; i++, mp++) { | for (i = 0, mp = mpoly; i < totpoly; i++, mp++) { | ||||
| const MLoop *loopstart = mloop + mp->loopstart; | const int *poly_verts = &corner_verts[mp->loopstart]; | ||||
| for (int j = 0; j < mp->totloop; j++) { | for (int j = 0; j < mp->totloop; j++) { | ||||
| uint v_prev = loopstart[(mp->totloop + (j - 1)) % mp->totloop].v; | const int v_prev = poly_verts[(mp->totloop + (j - 1)) % mp->totloop]; | ||||
| uint v_curr = loopstart[j].v; | const int v_curr = poly_verts[j]; | ||||
| uint v_next = loopstart[(j + 1) % mp->totloop].v; | const int v_next = poly_verts[(j + 1) % mp->totloop]; | ||||
| float tvec[3]; | float tvec[3]; | ||||
| transform_point_by_tri_v3(tvec, | transform_point_by_tri_v3(tvec, | ||||
| vert_cos_dst[v_curr], | vert_cos_dst[v_curr], | ||||
| vert_cos_org[v_prev], | vert_cos_org[v_prev], | ||||
| vert_cos_org[v_curr], | vert_cos_org[v_curr], | ||||
| vert_cos_org[v_next], | vert_cos_org[v_next], | ||||
| Show All 22 Lines | |||||