diff options
22 files changed, 967 insertions, 918 deletions
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index a1101c1df44..010fbb27172 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -550,33 +550,11 @@ void CustomData_validate_layer_name(const struct CustomData *data, */ bool CustomData_verify_versions(struct CustomData *data, int index); -/* BMesh specific custom-data stuff. - * - * Needed to convert to/from different face representation (for versioning). */ +/* BMesh specific custom-data stuff. */ -void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int totloop); -void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int total); void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct CustomData *ldata); -/** - * Update active indices for active/render/clone/stencil custom data layers - * based on indices from fdata layers - * used by do_versions in `readfile.c` when creating pdata and ldata for pre-bmesh - * meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files. - */ -void CustomData_bmesh_do_versions_update_active_layers(struct CustomData *fdata, - struct CustomData *ldata); void CustomData_bmesh_init_pool(struct CustomData *data, int totelem, char htype); -#ifndef NDEBUG -/** - * Debug check, used to assert when we expect layers to be in/out of sync. - * - * \param fallback: Use when there are no layers to handle, - * since callers may expect success or failure. - */ -bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback); -#endif - /** * Validate and fix data of \a layer, * if possible (needs relevant callback in layer's type to be defined). diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 66e0ff8e81a..ff4f4a8dc9e 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -183,14 +183,6 @@ void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totver */ void BKE_mesh_orco_ensure(struct Object *ob, struct Mesh *mesh); -/** - * Rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0. - * this is necessary to make the if #MFace.v4 check for quads work. - */ -int BKE_mesh_mface_index_validate(struct MFace *mface, - struct CustomData *mfdata, - int mfindex, - int nr); struct Mesh *BKE_mesh_from_object(struct Object *ob); void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me); void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me); @@ -304,7 +296,6 @@ bool BKE_mesh_minmax(const struct Mesh *me, float r_min[3], float r_max[3]); void BKE_mesh_transform(struct Mesh *me, const float mat[4][4], bool do_keys); void BKE_mesh_translate(struct Mesh *me, const float offset[3], bool do_keys); -void BKE_mesh_tessface_ensure(struct Mesh *mesh); void BKE_mesh_tessface_clear(struct Mesh *mesh); void BKE_mesh_do_versions_cd_flag_init(struct Mesh *mesh); @@ -334,15 +325,6 @@ void BKE_mesh_vert_coords_apply(struct Mesh *mesh, const float (*vert_coords)[3] /* *** mesh_tessellate.c *** */ /** - * Recreate #MFace Tessellation. - * - * \note This doesn't use multi-threading like #BKE_mesh_recalc_looptri since - * it's not used in many places and #MFace should be phased out. - */ - -void BKE_mesh_tessface_calc(struct Mesh *mesh); - -/** * Calculate tessellation into #MLoopTri which exist only for this purpose. */ void BKE_mesh_recalc_looptri(const struct MLoop *mloop, @@ -789,37 +771,6 @@ void BKE_mesh_calc_volume(const struct MVert *mverts, float *r_volume, float r_center[3]); -/* tessface */ -void BKE_mesh_convert_mfaces_to_mpolys(struct Mesh *mesh); -/** - * The same as #BKE_mesh_convert_mfaces_to_mpolys - * but oriented to be used in #do_versions from `readfile.c` - * the difference is how active/render/clone/stencil indices are handled here. - * - * normally they're being set from `pdata` which totally makes sense for meshes which are already - * converted to #BMesh structures, but when loading older files indices shall be updated in other - * way around, so newly added `pdata` and `ldata` would have this indices set - * based on `fdata` layer. - * - * this is normally only needed when reading older files, - * in all other cases #BKE_mesh_convert_mfaces_to_mpolys shall be always used. - */ -void BKE_mesh_do_versions_convert_mfaces_to_mpolys(struct Mesh *mesh); -void BKE_mesh_convert_mfaces_to_mpolys_ex(struct ID *id, - struct CustomData *fdata, - struct CustomData *ldata, - struct CustomData *pdata, - int totedge_i, - int totface_i, - int totloop_i, - int totpoly_i, - struct MEdge *medge, - struct MFace *mface, - int *r_totloop, - int *r_totpoly, - struct MLoop **r_mloop, - struct MPoly **r_mpoly); - /** * Flip a single MLoop's #MDisps structure, * low level function to be called from face-flipping code which re-arranged the mdisps themselves. @@ -1072,18 +1023,6 @@ char *BKE_mesh_debug_info(const struct Mesh *me) void BKE_mesh_debug_print(const struct Mesh *me) ATTR_NONNULL(1); #endif -/* Inlines */ - -/* NOTE(@sybren): Instead of -1 that function uses ORIGINDEX_NONE as defined in BKE_customdata.h, - * but I don't want to force every user of BKE_mesh.h to also include that file. */ -BLI_INLINE int BKE_mesh_origindex_mface_mpoly(const int *index_mf_to_mpoly, - const int *index_mp_to_orig, - const int i) -{ - const int j = index_mf_to_mpoly[i]; - return (j != -1) ? (index_mp_to_orig ? index_mp_to_orig[j] : j) : -1; -} - #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_mesh_legacy_convert.h b/source/blender/blenkernel/BKE_mesh_legacy_convert.h new file mode 100644 index 00000000000..909fd0e0dea --- /dev/null +++ b/source/blender/blenkernel/BKE_mesh_legacy_convert.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2001-2002 NaN Holding BV. All rights reserved. */ + +#pragma once + +/** \file + * \ingroup bke + */ + +#include "BLI_utildefines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct CustomData; +struct Mesh; +struct MFace; + +/** + * Recreate #MFace Tessellation. + * + * \note This doesn't use multi-threading like #BKE_mesh_recalc_looptri since + * it's not used in many places and #MFace should be phased out. + */ + +void BKE_mesh_tessface_calc(struct Mesh *mesh); + +void BKE_mesh_tessface_ensure(struct Mesh *mesh); + +void BKE_mesh_add_mface_layers(struct CustomData *fdata, struct CustomData *ldata, int total); + +/** + * Rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0. + * this is necessary to make the if #MFace.v4 check for quads work. + */ +int BKE_mesh_mface_index_validate(struct MFace *mface, + struct CustomData *mfdata, + int mfindex, + int nr); + +void BKE_mesh_convert_mfaces_to_mpolys(struct Mesh *mesh); + +/** + * The same as #BKE_mesh_convert_mfaces_to_mpolys + * but oriented to be used in #do_versions from `readfile.c` + * the difference is how active/render/clone/stencil indices are handled here. + * + * normally they're being set from `pdata` which totally makes sense for meshes which are already + * converted to #BMesh structures, but when loading older files indices shall be updated in other + * way around, so newly added `pdata` and `ldata` would have this indices set + * based on `fdata` layer. + * + * this is normally only needed when reading older files, + * in all other cases #BKE_mesh_convert_mfaces_to_mpolys shall be always used. + */ +void BKE_mesh_do_versions_convert_mfaces_to_mpolys(struct Mesh *mesh); + +/* Inlines */ + +/* NOTE(@sybren): Instead of -1 that function uses ORIGINDEX_NONE as defined in BKE_customdata.h, + * but I don't want to force every user of BKE_mesh.h to also include that file. */ +BLI_INLINE int BKE_mesh_origindex_mface_mpoly(const int *index_mf_to_mpoly, + const int *index_mp_to_orig, + const int i) +{ + const int j = index_mf_to_mpoly[i]; + return (j != -1) ? (index_mp_to_orig ? index_mp_to_orig[j] : j) : -1; +} + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 50be5b475d4..b2307c0e129 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -199,6 +199,7 @@ set(SRC intern/mesh_evaluate.cc intern/mesh_fair.cc intern/mesh_iterators.c + intern/mesh_legacy_convert.cc intern/mesh_mapping.c intern/mesh_merge.c intern/mesh_merge_customdata.cc @@ -419,6 +420,7 @@ set(SRC BKE_mesh_boolean_convert.hh BKE_mesh_fair.h BKE_mesh_iterators.h + BKE_mesh_legacy_convert.h BKE_mesh_mapping.h BKE_mesh_mirror.h BKE_mesh_remap.h diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 74903e72f91..26fbd7d7b54 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -3517,97 +3517,6 @@ void CustomData_set(const CustomData *data, int index, int type, const void *sou /* BMesh functions */ -void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop) -{ - for (int i = 0; i < fdata->totlayer; i++) { - if (fdata->layers[i].type == CD_MTFACE) { - CustomData_add_layer_named( - ldata, CD_MLOOPUV, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); - } - else if (fdata->layers[i].type == CD_MCOL) { - CustomData_add_layer_named( - ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); - } - else if (fdata->layers[i].type == CD_MDISPS) { - CustomData_add_layer_named( - ldata, CD_MDISPS, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); - } - else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) { - CustomData_add_layer_named( - ldata, CD_NORMAL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); - } - } -} - -void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *ldata, int total) -{ - /* avoid accumulating extra layers */ - BLI_assert(!CustomData_from_bmeshpoly_test(fdata, ldata, false)); - - for (int i = 0; i < ldata->totlayer; i++) { - if (ldata->layers[i].type == CD_MLOOPUV) { - CustomData_add_layer_named( - fdata, CD_MTFACE, CD_CALLOC, nullptr, total, ldata->layers[i].name); - } - if (ldata->layers[i].type == CD_PROP_BYTE_COLOR) { - CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name); - } - else if (ldata->layers[i].type == CD_PREVIEW_MLOOPCOL) { - CustomData_add_layer_named( - fdata, CD_PREVIEW_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name); - } - else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) { - CustomData_add_layer_named( - fdata, CD_ORIGSPACE, CD_CALLOC, nullptr, total, ldata->layers[i].name); - } - else if (ldata->layers[i].type == CD_NORMAL) { - CustomData_add_layer_named( - fdata, CD_TESSLOOPNORMAL, CD_CALLOC, nullptr, total, ldata->layers[i].name); - } - else if (ldata->layers[i].type == CD_TANGENT) { - CustomData_add_layer_named( - fdata, CD_TANGENT, CD_CALLOC, nullptr, total, ldata->layers[i].name); - } - } - - CustomData_bmesh_update_active_layers(fdata, ldata); -} - -#ifndef NDEBUG -bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback) -{ - int a_num = 0, b_num = 0; -# define LAYER_CMP(l_a, t_a, l_b, t_b) \ - ((a_num += CustomData_number_of_layers(l_a, t_a)) == \ - (b_num += CustomData_number_of_layers(l_b, t_b))) - - if (!LAYER_CMP(ldata, CD_MLOOPUV, fdata, CD_MTFACE)) { - return false; - } - if (!LAYER_CMP(ldata, CD_PROP_BYTE_COLOR, fdata, CD_MCOL)) { - return false; - } - if (!LAYER_CMP(ldata, CD_PREVIEW_MLOOPCOL, fdata, CD_PREVIEW_MCOL)) { - return false; - } - if (!LAYER_CMP(ldata, CD_ORIGSPACE_MLOOP, fdata, CD_ORIGSPACE)) { - return false; - } - if (!LAYER_CMP(ldata, CD_NORMAL, fdata, CD_TESSLOOPNORMAL)) { - return false; - } - if (!LAYER_CMP(ldata, CD_TANGENT, fdata, CD_TANGENT)) { - return false; - } - -# undef LAYER_CMP - - /* if no layers are on either CustomData's, - * then there was nothing to do... */ - return a_num ? true : fallback; -} -#endif - void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata) { int act; @@ -3641,38 +3550,7 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata) } } -void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *ldata) -{ - int act; - - if (CustomData_has_layer(fdata, CD_MTFACE)) { - act = CustomData_get_active_layer(fdata, CD_MTFACE); - CustomData_set_layer_active(ldata, CD_MLOOPUV, act); - act = CustomData_get_render_layer(fdata, CD_MTFACE); - CustomData_set_layer_render(ldata, CD_MLOOPUV, act); - - act = CustomData_get_clone_layer(fdata, CD_MTFACE); - CustomData_set_layer_clone(ldata, CD_MLOOPUV, act); - - act = CustomData_get_stencil_layer(fdata, CD_MTFACE); - CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act); - } - - if (CustomData_has_layer(fdata, CD_MCOL)) { - act = CustomData_get_active_layer(fdata, CD_MCOL); - CustomData_set_layer_active(ldata, CD_PROP_BYTE_COLOR, act); - - act = CustomData_get_render_layer(fdata, CD_MCOL); - CustomData_set_layer_render(ldata, CD_PROP_BYTE_COLOR, act); - - act = CustomData_get_clone_layer(fdata, CD_MCOL); - CustomData_set_layer_clone(ldata, CD_PROP_BYTE_COLOR, act); - - act = CustomData_get_stencil_layer(fdata, CD_MCOL); - CustomData_set_layer_stencil(ldata, CD_PROP_BYTE_COLOR, act); - } -} void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype) { diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index ffbd824712a..98fa551590c 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -47,6 +47,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" +#include "BKE_mesh_legacy_convert.h" #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" @@ -755,7 +756,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me) if (tottex_tessface != tottex_original || totcol_tessface != totcol_original) { BKE_mesh_tessface_clear(me); - CustomData_from_bmeshpoly(&me->fdata, &me->ldata, me->totface); + BKE_mesh_add_mface_layers(&me->fdata, &me->ldata, me->totface); /* TODO: add some `--debug-mesh` option. */ if (G.debug & G_DEBUG) { @@ -1352,74 +1353,6 @@ void BKE_mesh_orco_ensure(Object *ob, Mesh *mesh) CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, orcodata, mesh->totvert); } -int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex, int nr) -{ - /* first test if the face is legal */ - if ((mface->v3 || nr == 4) && mface->v3 == mface->v4) { - mface->v4 = 0; - nr--; - } - if ((mface->v2 || mface->v4) && mface->v2 == mface->v3) { - mface->v3 = mface->v4; - mface->v4 = 0; - nr--; - } - if (mface->v1 == mface->v2) { - mface->v2 = mface->v3; - mface->v3 = mface->v4; - mface->v4 = 0; - nr--; - } - - /* Check corrupt cases, bow-tie geometry, - * can't handle these because edge data won't exist so just return 0. */ - if (nr == 3) { - if ( - /* real edges */ - mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v1) { - return 0; - } - } - else if (nr == 4) { - if ( - /* real edges */ - mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v4 || - mface->v4 == mface->v1 || - /* across the face */ - mface->v1 == mface->v3 || mface->v2 == mface->v4) { - return 0; - } - } - - /* prevent a zero at wrong index location */ - if (nr == 3) { - if (mface->v3 == 0) { - static int corner_indices[4] = {1, 2, 0, 3}; - - SWAP(uint, mface->v1, mface->v2); - SWAP(uint, mface->v2, mface->v3); - - if (fdata) { - CustomData_swap_corners(fdata, mfindex, corner_indices); - } - } - } - else if (nr == 4) { - if (mface->v3 == 0 || mface->v4 == 0) { - static int corner_indices[4] = {2, 3, 0, 1}; - - SWAP(uint, mface->v1, mface->v3); - SWAP(uint, mface->v2, mface->v4); - - if (fdata) { - CustomData_swap_corners(fdata, mfindex, corner_indices); - } - } - } - - return nr; -} - Mesh *BKE_mesh_from_object(Object *ob) { if (ob == nullptr) { @@ -1709,13 +1642,6 @@ void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) BKE_mesh_tag_coords_changed_uniformly(me); } -void BKE_mesh_tessface_ensure(Mesh *mesh) -{ - if (mesh->totpoly && mesh->totface == 0) { - BKE_mesh_tessface_calc(mesh); - } -} - void BKE_mesh_tessface_clear(Mesh *mesh) { mesh_tessface_clear_intern(mesh, true); diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc index de0489d668f..7d26262a504 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.cc +++ b/source/blender/blenkernel/intern/mesh_evaluate.cc @@ -632,278 +632,6 @@ void BKE_mesh_calc_volume(const MVert *mverts, /** \} */ -/* -------------------------------------------------------------------- */ -/** \name NGon Tessellation (NGon to MFace Conversion) - * \{ */ - -static void bm_corners_to_loops_ex(ID *id, - CustomData *fdata, - CustomData *ldata, - MFace *mface, - int totloop, - int findex, - int loopstart, - int numTex, - int numCol) -{ - MFace *mf = mface + findex; - - for (int i = 0; i < numTex; i++) { - const MTFace *texface = (const MTFace *)CustomData_get_n(fdata, CD_MTFACE, findex, i); - - MLoopUV *mloopuv = (MLoopUV *)CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i); - copy_v2_v2(mloopuv->uv, texface->uv[0]); - mloopuv++; - copy_v2_v2(mloopuv->uv, texface->uv[1]); - mloopuv++; - copy_v2_v2(mloopuv->uv, texface->uv[2]); - mloopuv++; - - if (mf->v4) { - copy_v2_v2(mloopuv->uv, texface->uv[3]); - mloopuv++; - } - } - - for (int i = 0; i < numCol; i++) { - MLoopCol *mloopcol = (MLoopCol *)CustomData_get_n(ldata, CD_PROP_BYTE_COLOR, loopstart, i); - const MCol *mcol = (const MCol *)CustomData_get_n(fdata, CD_MCOL, findex, i); - - MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[0]); - mloopcol++; - MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[1]); - mloopcol++; - MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[2]); - mloopcol++; - if (mf->v4) { - MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[3]); - mloopcol++; - } - } - - if (CustomData_has_layer(fdata, CD_TESSLOOPNORMAL)) { - float(*lnors)[3] = (float(*)[3])CustomData_get(ldata, loopstart, CD_NORMAL); - const short(*tlnors)[3] = (short(*)[3])CustomData_get(fdata, findex, CD_TESSLOOPNORMAL); - const int max = mf->v4 ? 4 : 3; - - for (int i = 0; i < max; i++, lnors++, tlnors++) { - normal_short_to_float_v3(*lnors, *tlnors); - } - } - - if (CustomData_has_layer(fdata, CD_MDISPS)) { - MDisps *ld = (MDisps *)CustomData_get(ldata, loopstart, CD_MDISPS); - const MDisps *fd = (const MDisps *)CustomData_get(fdata, findex, CD_MDISPS); - const float(*disps)[3] = fd->disps; - int tot = mf->v4 ? 4 : 3; - int corners; - - if (CustomData_external_test(fdata, CD_MDISPS)) { - if (id && fdata->external) { - CustomData_external_add(ldata, id, CD_MDISPS, totloop, fdata->external->filepath); - } - } - - corners = multires_mdisp_corners(fd); - - if (corners == 0) { - /* Empty #MDisp layers appear in at least one of the `sintel.blend` files. - * Not sure why this happens, but it seems fine to just ignore them here. - * If `corners == 0` for a non-empty layer though, something went wrong. */ - BLI_assert(fd->totdisp == 0); - } - else { - const int side = (int)sqrtf((float)(fd->totdisp / corners)); - const int side_sq = side * side; - - for (int i = 0; i < tot; i++, disps += side_sq, ld++) { - ld->totdisp = side_sq; - ld->level = (int)(logf((float)side - 1.0f) / (float)M_LN2) + 1; - - if (ld->disps) { - MEM_freeN(ld->disps); - } - - ld->disps = (float(*)[3])MEM_malloc_arrayN( - (size_t)side_sq, sizeof(float[3]), "converted loop mdisps"); - if (fd->disps) { - memcpy(ld->disps, disps, (size_t)side_sq * sizeof(float[3])); - } - else { - memset(ld->disps, 0, (size_t)side_sq * sizeof(float[3])); - } - } - } - } -} - -void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh) -{ - BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id, - &mesh->fdata, - &mesh->ldata, - &mesh->pdata, - mesh->totedge, - mesh->totface, - mesh->totloop, - mesh->totpoly, - mesh->medge, - mesh->mface, - &mesh->totloop, - &mesh->totpoly, - &mesh->mloop, - &mesh->mpoly); - - BKE_mesh_update_customdata_pointers(mesh, true); -} - -void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh) -{ - BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id, - &mesh->fdata, - &mesh->ldata, - &mesh->pdata, - mesh->totedge, - mesh->totface, - mesh->totloop, - mesh->totpoly, - mesh->medge, - mesh->mface, - &mesh->totloop, - &mesh->totpoly, - &mesh->mloop, - &mesh->mpoly); - - CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata); - - BKE_mesh_update_customdata_pointers(mesh, true); -} - -void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, - CustomData *fdata, - CustomData *ldata, - CustomData *pdata, - int totedge_i, - int totface_i, - int totloop_i, - int totpoly_i, - MEdge *medge, - MFace *mface, - int *r_totloop, - int *r_totpoly, - MLoop **r_mloop, - MPoly **r_mpoly) -{ - MFace *mf; - MLoop *ml, *mloop; - MPoly *mp, *mpoly; - MEdge *me; - EdgeHash *eh; - int numTex, numCol; - int i, j, totloop, totpoly, *polyindex; - - /* old flag, clear to allow for reuse */ -#define ME_FGON (1 << 3) - - /* just in case some of these layers are filled in (can happen with python created meshes) */ - CustomData_free(ldata, totloop_i); - CustomData_free(pdata, totpoly_i); - - totpoly = totface_i; - mpoly = (MPoly *)MEM_calloc_arrayN((size_t)totpoly, sizeof(MPoly), "mpoly converted"); - CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, totpoly); - - numTex = CustomData_number_of_layers(fdata, CD_MTFACE); - numCol = CustomData_number_of_layers(fdata, CD_MCOL); - - totloop = 0; - mf = mface; - for (i = 0; i < totface_i; i++, mf++) { - totloop += mf->v4 ? 4 : 3; - } - - mloop = (MLoop *)MEM_calloc_arrayN((size_t)totloop, sizeof(MLoop), "mloop converted"); - - CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop); - - CustomData_to_bmeshpoly(fdata, ldata, totloop); - - if (id) { - /* ensure external data is transferred */ - /* TODO(sergey): Use multiresModifier_ensure_external_read(). */ - CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i); - } - - eh = BLI_edgehash_new_ex(__func__, (uint)totedge_i); - - /* build edge hash */ - me = medge; - for (i = 0; i < totedge_i; i++, me++) { - BLI_edgehash_insert(eh, me->v1, me->v2, POINTER_FROM_UINT(i)); - - /* unrelated but avoid having the FGON flag enabled, - * so we can reuse it later for something else */ - me->flag &= ~ME_FGON; - } - - polyindex = (int *)CustomData_get_layer(fdata, CD_ORIGINDEX); - - j = 0; /* current loop index */ - ml = mloop; - mf = mface; - mp = mpoly; - for (i = 0; i < totface_i; i++, mf++, mp++) { - mp->loopstart = j; - - mp->totloop = mf->v4 ? 4 : 3; - - mp->mat_nr = mf->mat_nr; - mp->flag = mf->flag; - -#define ML(v1, v2) \ - { \ - ml->v = mf->v1; \ - ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); \ - ml++; \ - j++; \ - } \ - (void)0 - - ML(v1, v2); - ML(v2, v3); - if (mf->v4) { - ML(v3, v4); - ML(v4, v1); - } - else { - ML(v3, v1); - } - -#undef ML - - bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol); - - if (polyindex) { - *polyindex = i; - polyindex++; - } - } - - /* NOTE: we don't convert NGons at all, these are not even real ngons, - * they have their own UV's, colors etc - its more an editing feature. */ - - BLI_edgehash_free(eh, nullptr); - - *r_totpoly = totpoly; - *r_totloop = totloop; - *r_mpoly = mpoly; - *r_mloop = mloop; - -#undef ME_FGON -} - -/** \} */ - void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip) { if (UNLIKELY(!md->totdisp || !md->disps)) { diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc new file mode 100644 index 00000000000..479dd6a012a --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -0,0 +1,876 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2001-2002 NaN Holding BV. All rights reserved. */ + +/** \file + * \ingroup bke + * + * Functions to convert mesh data to and from legacy formats like #MFace. + */ + +// #include <climits> + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_edgehash.h" +#include "BLI_math.h" +#include "BLI_memarena.h" +#include "BLI_polyfill_2d.h" +#include "BLI_utildefines.h" + +#include "BKE_customdata.h" +#include "BKE_mesh.h" +#include "BKE_mesh_legacy_convert.h" +#include "BKE_multires.h" + +/* -------------------------------------------------------------------- */ +/** \name NGon Tessellation (NGon to MFace Conversion) + * \{ */ + +static void bm_corners_to_loops_ex(ID *id, + CustomData *fdata, + CustomData *ldata, + MFace *mface, + int totloop, + int findex, + int loopstart, + int numTex, + int numCol) +{ + MFace *mf = mface + findex; + + for (int i = 0; i < numTex; i++) { + const MTFace *texface = (const MTFace *)CustomData_get_n(fdata, CD_MTFACE, findex, i); + + MLoopUV *mloopuv = (MLoopUV *)CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i); + copy_v2_v2(mloopuv->uv, texface->uv[0]); + mloopuv++; + copy_v2_v2(mloopuv->uv, texface->uv[1]); + mloopuv++; + copy_v2_v2(mloopuv->uv, texface->uv[2]); + mloopuv++; + + if (mf->v4) { + copy_v2_v2(mloopuv->uv, texface->uv[3]); + mloopuv++; + } + } + + for (int i = 0; i < numCol; i++) { + MLoopCol *mloopcol = (MLoopCol *)CustomData_get_n(ldata, CD_PROP_BYTE_COLOR, loopstart, i); + const MCol *mcol = (const MCol *)CustomData_get_n(fdata, CD_MCOL, findex, i); + + MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[0]); + mloopcol++; + MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[1]); + mloopcol++; + MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[2]); + mloopcol++; + if (mf->v4) { + MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[3]); + mloopcol++; + } + } + + if (CustomData_has_layer(fdata, CD_TESSLOOPNORMAL)) { + float(*lnors)[3] = (float(*)[3])CustomData_get(ldata, loopstart, CD_NORMAL); + const short(*tlnors)[3] = (short(*)[3])CustomData_get(fdata, findex, CD_TESSLOOPNORMAL); + const int max = mf->v4 ? 4 : 3; + + for (int i = 0; i < max; i++, lnors++, tlnors++) { + normal_short_to_float_v3(*lnors, *tlnors); + } + } + + if (CustomData_has_layer(fdata, CD_MDISPS)) { + MDisps *ld = (MDisps *)CustomData_get(ldata, loopstart, CD_MDISPS); + const MDisps *fd = (const MDisps *)CustomData_get(fdata, findex, CD_MDISPS); + const float(*disps)[3] = fd->disps; + int tot = mf->v4 ? 4 : 3; + int corners; + + if (CustomData_external_test(fdata, CD_MDISPS)) { + if (id && fdata->external) { + CustomData_external_add(ldata, id, CD_MDISPS, totloop, fdata->external->filepath); + } + } + + corners = multires_mdisp_corners(fd); + + if (corners == 0) { + /* Empty #MDisp layers appear in at least one of the `sintel.blend` files. + * Not sure why this happens, but it seems fine to just ignore them here. + * If `corners == 0` for a non-empty layer though, something went wrong. */ + BLI_assert(fd->totdisp == 0); + } + else { + const int side = (int)sqrtf((float)(fd->totdisp / corners)); + const int side_sq = side * side; + + for (int i = 0; i < tot; i++, disps += side_sq, ld++) { + ld->totdisp = side_sq; + ld->level = (int)(logf((float)side - 1.0f) / (float)M_LN2) + 1; + + if (ld->disps) { + MEM_freeN(ld->disps); + } + + ld->disps = (float(*)[3])MEM_malloc_arrayN( + (size_t)side_sq, sizeof(float[3]), "converted loop mdisps"); + if (fd->disps) { + memcpy(ld->disps, disps, (size_t)side_sq * sizeof(float[3])); + } + else { + memset(ld->disps, 0, (size_t)side_sq * sizeof(float[3])); + } + } + } + } +} + +static void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop) +{ + for (int i = 0; i < fdata->totlayer; i++) { + if (fdata->layers[i].type == CD_MTFACE) { + CustomData_add_layer_named( + ldata, CD_MLOOPUV, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + } + else if (fdata->layers[i].type == CD_MCOL) { + CustomData_add_layer_named( + ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + } + else if (fdata->layers[i].type == CD_MDISPS) { + CustomData_add_layer_named( + ldata, CD_MDISPS, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + } + else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) { + CustomData_add_layer_named( + ldata, CD_NORMAL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + } + } +} + +static void convert_mfaces_to_mpolys(ID *id, + CustomData *fdata, + CustomData *ldata, + CustomData *pdata, + int totedge_i, + int totface_i, + int totloop_i, + int totpoly_i, + MEdge *medge, + MFace *mface, + int *r_totloop, + int *r_totpoly, + MLoop **r_mloop, + MPoly **r_mpoly) +{ + MFace *mf; + MLoop *ml, *mloop; + MPoly *mp, *mpoly; + MEdge *me; + EdgeHash *eh; + int numTex, numCol; + int i, j, totloop, totpoly, *polyindex; + + /* old flag, clear to allow for reuse */ +#define ME_FGON (1 << 3) + + /* just in case some of these layers are filled in (can happen with python created meshes) */ + CustomData_free(ldata, totloop_i); + CustomData_free(pdata, totpoly_i); + + totpoly = totface_i; + mpoly = (MPoly *)MEM_calloc_arrayN((size_t)totpoly, sizeof(MPoly), "mpoly converted"); + CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, totpoly); + + numTex = CustomData_number_of_layers(fdata, CD_MTFACE); + numCol = CustomData_number_of_layers(fdata, CD_MCOL); + + totloop = 0; + mf = mface; + for (i = 0; i < totface_i; i++, mf++) { + totloop += mf->v4 ? 4 : 3; + } + + mloop = (MLoop *)MEM_calloc_arrayN((size_t)totloop, sizeof(MLoop), "mloop converted"); + + CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop); + + CustomData_to_bmeshpoly(fdata, ldata, totloop); + + if (id) { + /* ensure external data is transferred */ + /* TODO(sergey): Use multiresModifier_ensure_external_read(). */ + CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i); + } + + eh = BLI_edgehash_new_ex(__func__, (uint)totedge_i); + + /* build edge hash */ + me = medge; + for (i = 0; i < totedge_i; i++, me++) { + BLI_edgehash_insert(eh, me->v1, me->v2, POINTER_FROM_UINT(i)); + + /* unrelated but avoid having the FGON flag enabled, + * so we can reuse it later for something else */ + me->flag &= ~ME_FGON; + } + + polyindex = (int *)CustomData_get_layer(fdata, CD_ORIGINDEX); + + j = 0; /* current loop index */ + ml = mloop; + mf = mface; + mp = mpoly; + for (i = 0; i < totface_i; i++, mf++, mp++) { + mp->loopstart = j; + + mp->totloop = mf->v4 ? 4 : 3; + + mp->mat_nr = mf->mat_nr; + mp->flag = mf->flag; + +#define ML(v1, v2) \ + { \ + ml->v = mf->v1; \ + ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); \ + ml++; \ + j++; \ + } \ + (void)0 + + ML(v1, v2); + ML(v2, v3); + if (mf->v4) { + ML(v3, v4); + ML(v4, v1); + } + else { + ML(v3, v1); + } + +#undef ML + + bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol); + + if (polyindex) { + *polyindex = i; + polyindex++; + } + } + + /* NOTE: we don't convert NGons at all, these are not even real ngons, + * they have their own UV's, colors etc - its more an editing feature. */ + + BLI_edgehash_free(eh, nullptr); + + *r_totpoly = totpoly; + *r_totloop = totloop; + *r_mpoly = mpoly; + *r_mloop = mloop; + +#undef ME_FGON +} + +void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh) +{ + convert_mfaces_to_mpolys(&mesh->id, + &mesh->fdata, + &mesh->ldata, + &mesh->pdata, + mesh->totedge, + mesh->totface, + mesh->totloop, + mesh->totpoly, + mesh->medge, + mesh->mface, + &mesh->totloop, + &mesh->totpoly, + &mesh->mloop, + &mesh->mpoly); + + BKE_mesh_update_customdata_pointers(mesh, true); +} + +/** + * Update active indices for active/render/clone/stencil custom data layers + * based on indices from fdata layers + * used when creating pdata and ldata for pre-bmesh + * meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files. + */ +static void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *ldata) +{ + int act; + + if (CustomData_has_layer(fdata, CD_MTFACE)) { + act = CustomData_get_active_layer(fdata, CD_MTFACE); + CustomData_set_layer_active(ldata, CD_MLOOPUV, act); + + act = CustomData_get_render_layer(fdata, CD_MTFACE); + CustomData_set_layer_render(ldata, CD_MLOOPUV, act); + + act = CustomData_get_clone_layer(fdata, CD_MTFACE); + CustomData_set_layer_clone(ldata, CD_MLOOPUV, act); + + act = CustomData_get_stencil_layer(fdata, CD_MTFACE); + CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act); + } + + if (CustomData_has_layer(fdata, CD_MCOL)) { + act = CustomData_get_active_layer(fdata, CD_MCOL); + CustomData_set_layer_active(ldata, CD_PROP_BYTE_COLOR, act); + + act = CustomData_get_render_layer(fdata, CD_MCOL); + CustomData_set_layer_render(ldata, CD_PROP_BYTE_COLOR, act); + + act = CustomData_get_clone_layer(fdata, CD_MCOL); + CustomData_set_layer_clone(ldata, CD_PROP_BYTE_COLOR, act); + + act = CustomData_get_stencil_layer(fdata, CD_MCOL); + CustomData_set_layer_stencil(ldata, CD_PROP_BYTE_COLOR, act); + } +} + +void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh) +{ + convert_mfaces_to_mpolys(&mesh->id, + &mesh->fdata, + &mesh->ldata, + &mesh->pdata, + mesh->totedge, + mesh->totface, + mesh->totloop, + mesh->totpoly, + mesh->medge, + mesh->mface, + &mesh->totloop, + &mesh->totpoly, + &mesh->mloop, + &mesh->mpoly); + + CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata); + + BKE_mesh_update_customdata_pointers(mesh, true); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name MFace Tessellation + * + * #MFace is a legacy data-structure that should be avoided, use #MLoopTri instead. + * \{ */ + +/** + * Convert all CD layers from loop/poly to tessface data. + * + * \param loopindices: is an array of an int[4] per tessface, + * mapping tessface's verts to loops indices. + * + * \note when mface is not null, mface[face_index].v4 + * is used to test quads, else, loopindices[face_index][3] is used. + */ +static void mesh_loops_to_tessdata(CustomData *fdata, + CustomData *ldata, + MFace *mface, + const int *polyindices, + uint (*loopindices)[4], + const int num_faces) +{ + /* NOTE(mont29): performances are sub-optimal when we get a null #MFace, + * we could be ~25% quicker with dedicated code. + * The issue is, unless having two different functions with nearly the same code, + * there's not much ways to solve this. Better IMHO to live with it for now (sigh). */ + const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV); + const int numCol = CustomData_number_of_layers(ldata, CD_PROP_BYTE_COLOR); + const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL); + const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP); + const bool hasLoopNormal = CustomData_has_layer(ldata, CD_NORMAL); + const bool hasLoopTangent = CustomData_has_layer(ldata, CD_TANGENT); + int findex, i, j; + const int *pidx; + uint(*lidx)[4]; + + for (i = 0; i < numUV; i++) { + MTFace *texface = (MTFace *)CustomData_get_layer_n(fdata, CD_MTFACE, i); + const MLoopUV *mloopuv = (const MLoopUV *)CustomData_get_layer_n(ldata, CD_MLOOPUV, i); + + for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces; + pidx++, lidx++, findex++, texface++) { + for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) { + copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv); + } + } + } + + for (i = 0; i < numCol; i++) { + MCol(*mcol)[4] = (MCol(*)[4])CustomData_get_layer_n(fdata, CD_MCOL, i); + const MLoopCol *mloopcol = (const MLoopCol *)CustomData_get_layer_n( + ldata, CD_PROP_BYTE_COLOR, i); + + for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) { + for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) { + MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]); + } + } + } + + if (hasPCol) { + MCol(*mcol)[4] = (MCol(*)[4])CustomData_get_layer(fdata, CD_PREVIEW_MCOL); + const MLoopCol *mloopcol = (const MLoopCol *)CustomData_get_layer(ldata, CD_PREVIEW_MLOOPCOL); + + for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) { + for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) { + MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]); + } + } + } + + if (hasOrigSpace) { + OrigSpaceFace *of = (OrigSpaceFace *)CustomData_get_layer(fdata, CD_ORIGSPACE); + const OrigSpaceLoop *lof = (const OrigSpaceLoop *)CustomData_get_layer(ldata, + CD_ORIGSPACE_MLOOP); + + for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, of++) { + for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) { + copy_v2_v2(of->uv[j], lof[(*lidx)[j]].uv); + } + } + } + + if (hasLoopNormal) { + short(*fnors)[4][3] = (short(*)[4][3])CustomData_get_layer(fdata, CD_TESSLOOPNORMAL); + const float(*lnors)[3] = (const float(*)[3])CustomData_get_layer(ldata, CD_NORMAL); + + for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, fnors++) { + for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) { + normal_float_to_short_v3((*fnors)[j], lnors[(*lidx)[j]]); + } + } + } + + if (hasLoopTangent) { + /* Need to do for all UV maps at some point. */ + float(*ftangents)[4] = (float(*)[4])CustomData_get_layer(fdata, CD_TANGENT); + const float(*ltangents)[4] = (const float(*)[4])CustomData_get_layer(ldata, CD_TANGENT); + + for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces; + pidx++, lidx++, findex++) { + int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; + for (j = nverts; j--;) { + copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]); + } + } + } +} + +int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex, int nr) +{ + /* first test if the face is legal */ + if ((mface->v3 || nr == 4) && mface->v3 == mface->v4) { + mface->v4 = 0; + nr--; + } + if ((mface->v2 || mface->v4) && mface->v2 == mface->v3) { + mface->v3 = mface->v4; + mface->v4 = 0; + nr--; + } + if (mface->v1 == mface->v2) { + mface->v2 = mface->v3; + mface->v3 = mface->v4; + mface->v4 = 0; + nr--; + } + + /* Check corrupt cases, bow-tie geometry, + * can't handle these because edge data won't exist so just return 0. */ + if (nr == 3) { + if ( + /* real edges */ + mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v1) { + return 0; + } + } + else if (nr == 4) { + if ( + /* real edges */ + mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v4 || + mface->v4 == mface->v1 || + /* across the face */ + mface->v1 == mface->v3 || mface->v2 == mface->v4) { + return 0; + } + } + + /* prevent a zero at wrong index location */ + if (nr == 3) { + if (mface->v3 == 0) { + static int corner_indices[4] = {1, 2, 0, 3}; + + SWAP(uint, mface->v1, mface->v2); + SWAP(uint, mface->v2, mface->v3); + + if (fdata) { + CustomData_swap_corners(fdata, mfindex, corner_indices); + } + } + } + else if (nr == 4) { + if (mface->v3 == 0 || mface->v4 == 0) { + static int corner_indices[4] = {2, 3, 0, 1}; + + SWAP(uint, mface->v1, mface->v3); + SWAP(uint, mface->v2, mface->v4); + + if (fdata) { + CustomData_swap_corners(fdata, mfindex, corner_indices); + } + } + } + + return nr; +} + +static int mesh_tessface_calc(CustomData *fdata, + CustomData *ldata, + CustomData *pdata, + MVert *mvert, + int totface, + int totloop, + int totpoly) +{ +#define USE_TESSFACE_SPEEDUP +#define USE_TESSFACE_QUADS + +/* We abuse #MFace.edcode to tag quad faces. See below for details. */ +#define TESSFACE_IS_QUAD 1 + + const int looptri_num = poly_to_tri_count(totpoly, totloop); + + const MPoly *mp, *mpoly; + const MLoop *ml, *mloop; + MFace *mface, *mf; + MemArena *arena = nullptr; + int *mface_to_poly_map; + uint(*lindices)[4]; + int poly_index, mface_index; + uint j; + + mpoly = (const MPoly *)CustomData_get_layer(pdata, CD_MPOLY); + mloop = (const MLoop *)CustomData_get_layer(ldata, CD_MLOOP); + + /* Allocate the length of `totfaces`, avoid many small reallocation's, + * if all faces are triangles it will be correct, `quads == 2x` allocations. */ + /* Take care since memory is _not_ zeroed so be sure to initialize each field. */ + mface_to_poly_map = (int *)MEM_malloc_arrayN( + (size_t)looptri_num, sizeof(*mface_to_poly_map), __func__); + mface = (MFace *)MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface), __func__); + lindices = (uint(*)[4])MEM_malloc_arrayN((size_t)looptri_num, sizeof(*lindices), __func__); + + mface_index = 0; + mp = mpoly; + for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) { + const uint mp_loopstart = (uint)mp->loopstart; + const uint mp_totloop = (uint)mp->totloop; + uint l1, l2, l3, l4; + uint *lidx; + if (mp_totloop < 3) { + /* Do nothing. */ + } + +#ifdef USE_TESSFACE_SPEEDUP + +# define ML_TO_MF(i1, i2, i3) \ + mface_to_poly_map[mface_index] = poly_index; \ + mf = &mface[mface_index]; \ + lidx = lindices[mface_index]; \ + /* Set loop indices, transformed to vert indices later. */ \ + l1 = mp_loopstart + i1; \ + l2 = mp_loopstart + i2; \ + l3 = mp_loopstart + i3; \ + mf->v1 = mloop[l1].v; \ + mf->v2 = mloop[l2].v; \ + mf->v3 = mloop[l3].v; \ + mf->v4 = 0; \ + lidx[0] = l1; \ + lidx[1] = l2; \ + lidx[2] = l3; \ + lidx[3] = 0; \ + mf->mat_nr = mp->mat_nr; \ + mf->flag = mp->flag; \ + mf->edcode = 0; \ + (void)0 + +/* ALMOST IDENTICAL TO DEFINE ABOVE (see EXCEPTION) */ +# define ML_TO_MF_QUAD() \ + mface_to_poly_map[mface_index] = poly_index; \ + mf = &mface[mface_index]; \ + lidx = lindices[mface_index]; \ + /* Set loop indices, transformed to vert indices later. */ \ + l1 = mp_loopstart + 0; /* EXCEPTION */ \ + l2 = mp_loopstart + 1; /* EXCEPTION */ \ + l3 = mp_loopstart + 2; /* EXCEPTION */ \ + l4 = mp_loopstart + 3; /* EXCEPTION */ \ + mf->v1 = mloop[l1].v; \ + mf->v2 = mloop[l2].v; \ + mf->v3 = mloop[l3].v; \ + mf->v4 = mloop[l4].v; \ + lidx[0] = l1; \ + lidx[1] = l2; \ + lidx[2] = l3; \ + lidx[3] = l4; \ + mf->mat_nr = mp->mat_nr; \ + mf->flag = mp->flag; \ + mf->edcode = TESSFACE_IS_QUAD; \ + (void)0 + + else if (mp_totloop == 3) { + ML_TO_MF(0, 1, 2); + mface_index++; + } + else if (mp_totloop == 4) { +# ifdef USE_TESSFACE_QUADS + ML_TO_MF_QUAD(); + mface_index++; +# else + ML_TO_MF(0, 1, 2); + mface_index++; + ML_TO_MF(0, 2, 3); + mface_index++; +# endif + } +#endif /* USE_TESSFACE_SPEEDUP */ + else { + const float *co_curr, *co_prev; + + float normal[3]; + + float axis_mat[3][3]; + float(*projverts)[2]; + uint(*tris)[3]; + + const uint totfilltri = mp_totloop - 2; + + if (UNLIKELY(arena == nullptr)) { + arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + } + + tris = (uint(*)[3])BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri); + projverts = (float(*)[2])BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop); + + zero_v3(normal); + + /* Calculate the normal, flipped: to get a positive 2D cross product. */ + ml = mloop + mp_loopstart; + co_prev = mvert[ml[mp_totloop - 1].v].co; + for (j = 0; j < mp_totloop; j++, ml++) { + co_curr = mvert[ml->v].co; + add_newell_cross_v3_v3v3(normal, co_prev, co_curr); + co_prev = co_curr; + } + if (UNLIKELY(normalize_v3(normal) == 0.0f)) { + normal[2] = 1.0f; + } + + /* Project verts to 2D. */ + axis_dominant_v3_to_m3_negate(axis_mat, normal); + + ml = mloop + mp_loopstart; + for (j = 0; j < mp_totloop; j++, ml++) { + mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co); + } + + BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena); + + /* Apply fill. */ + for (j = 0; j < totfilltri; j++) { + uint *tri = tris[j]; + lidx = lindices[mface_index]; + + mface_to_poly_map[mface_index] = poly_index; + mf = &mface[mface_index]; + + /* Set loop indices, transformed to vert indices later. */ + l1 = mp_loopstart + tri[0]; + l2 = mp_loopstart + tri[1]; + l3 = mp_loopstart + tri[2]; + + mf->v1 = mloop[l1].v; + mf->v2 = mloop[l2].v; + mf->v3 = mloop[l3].v; + mf->v4 = 0; + + lidx[0] = l1; + lidx[1] = l2; + lidx[2] = l3; + lidx[3] = 0; + + mf->mat_nr = mp->mat_nr; + mf->flag = mp->flag; + mf->edcode = 0; + + mface_index++; + } + + BLI_memarena_clear(arena); + } + } + + if (arena) { + BLI_memarena_free(arena); + arena = nullptr; + } + + CustomData_free(fdata, totface); + totface = mface_index; + + BLI_assert(totface <= looptri_num); + + /* Not essential but without this we store over-allocated memory in the #CustomData layers. */ + if (LIKELY(looptri_num != totface)) { + mface = (MFace *)MEM_reallocN(mface, sizeof(*mface) * (size_t)totface); + mface_to_poly_map = (int *)MEM_reallocN(mface_to_poly_map, + sizeof(*mface_to_poly_map) * (size_t)totface); + } + + CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface); + + /* #CD_ORIGINDEX will contain an array of indices from tessellation-faces to the polygons + * they are directly tessellated from. */ + CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface); + BKE_mesh_add_mface_layers(fdata, ldata, totface); + + /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx: + * Polygons take care of their loops ordering, hence not of their vertices ordering. + * Currently, our tfaces' fourth vertex index might be 0 even for a quad. + * However, we know our fourth loop index is never 0 for quads + * (because they are sorted for polygons, and our quads are still mere copies of their polygons). + * So we pass nullptr as MFace pointer, and #mesh_loops_to_tessdata + * will use the fourth loop index as quad test. */ + mesh_loops_to_tessdata(fdata, ldata, nullptr, mface_to_poly_map, lindices, totface); + + /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx: + * ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad. + * BKE_mesh_mface_index_validate() will check this and rotate the tessellated face if needed. + */ +#ifdef USE_TESSFACE_QUADS + mf = mface; + for (mface_index = 0; mface_index < totface; mface_index++, mf++) { + if (mf->edcode == TESSFACE_IS_QUAD) { + BKE_mesh_mface_index_validate(mf, fdata, mface_index, 4); + mf->edcode = 0; + } + } +#endif + + MEM_freeN(lindices); + + return totface; + +#undef USE_TESSFACE_SPEEDUP +#undef USE_TESSFACE_QUADS + +#undef ML_TO_MF +#undef ML_TO_MF_QUAD +} + +void BKE_mesh_tessface_calc(Mesh *mesh) +{ + mesh->totface = mesh_tessface_calc(&mesh->fdata, + &mesh->ldata, + &mesh->pdata, + mesh->mvert, + mesh->totface, + mesh->totloop, + mesh->totpoly); + + BKE_mesh_update_customdata_pointers(mesh, true); +} + +void BKE_mesh_tessface_ensure(struct Mesh *mesh) +{ + if (mesh->totpoly && mesh->totface == 0) { + BKE_mesh_tessface_calc(mesh); + } +} + +#ifndef NDEBUG +/** + * Debug check, used to assert when we expect layers to be in/out of sync. + * + * \param fallback: Use when there are no layers to handle, + * since callers may expect success or failure. + */ +static bool check_matching_legacy_layer_counts(CustomData *fdata, CustomData *ldata, bool fallback) +{ + int a_num = 0, b_num = 0; +# define LAYER_CMP(l_a, t_a, l_b, t_b) \ + ((a_num += CustomData_number_of_layers(l_a, t_a)) == \ + (b_num += CustomData_number_of_layers(l_b, t_b))) + + if (!LAYER_CMP(ldata, CD_MLOOPUV, fdata, CD_MTFACE)) { + return false; + } + if (!LAYER_CMP(ldata, CD_PROP_BYTE_COLOR, fdata, CD_MCOL)) { + return false; + } + if (!LAYER_CMP(ldata, CD_PREVIEW_MLOOPCOL, fdata, CD_PREVIEW_MCOL)) { + return false; + } + if (!LAYER_CMP(ldata, CD_ORIGSPACE_MLOOP, fdata, CD_ORIGSPACE)) { + return false; + } + if (!LAYER_CMP(ldata, CD_NORMAL, fdata, CD_TESSLOOPNORMAL)) { + return false; + } + if (!LAYER_CMP(ldata, CD_TANGENT, fdata, CD_TANGENT)) { + return false; + } + +# undef LAYER_CMP + + /* if no layers are on either CustomData's, + * then there was nothing to do... */ + return a_num ? true : fallback; +} +#endif + +void BKE_mesh_add_mface_layers(CustomData *fdata, CustomData *ldata, int total) +{ + /* avoid accumulating extra layers */ + BLI_assert(!check_matching_legacy_layer_counts(fdata, ldata, false)); + + for (int i = 0; i < ldata->totlayer; i++) { + if (ldata->layers[i].type == CD_MLOOPUV) { + CustomData_add_layer_named( + fdata, CD_MTFACE, CD_CALLOC, nullptr, total, ldata->layers[i].name); + } + if (ldata->layers[i].type == CD_PROP_BYTE_COLOR) { + CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name); + } + else if (ldata->layers[i].type == CD_PREVIEW_MLOOPCOL) { + CustomData_add_layer_named( + fdata, CD_PREVIEW_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name); + } + else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) { + CustomData_add_layer_named( + fdata, CD_ORIGSPACE, CD_CALLOC, nullptr, total, ldata->layers[i].name); + } + else if (ldata->layers[i].type == CD_NORMAL) { + CustomData_add_layer_named( + fdata, CD_TESSLOOPNORMAL, CD_CALLOC, nullptr, total, ldata->layers[i].name); + } + else if (ldata->layers[i].type == CD_TANGENT) { + CustomData_add_layer_named( + fdata, CD_TANGENT, CD_CALLOC, nullptr, total, ldata->layers[i].name); + } + } + + CustomData_bmesh_update_active_layers(fdata, ldata); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/mesh_tessellate.c b/source/blender/blenkernel/intern/mesh_tessellate.c index 71d5722cb0e..173fb98912b 100644 --- a/source/blender/blenkernel/intern/mesh_tessellate.c +++ b/source/blender/blenkernel/intern/mesh_tessellate.c @@ -32,370 +32,6 @@ #define MESH_FACE_TESSELLATE_THREADED_LIMIT 4096 /* -------------------------------------------------------------------- */ -/** \name MFace Tessellation - * - * #MFace is a legacy data-structure that should be avoided, use #MLoopTri instead. - * \{ */ - -/** - * Convert all CD layers from loop/poly to tessface data. - * - * \param loopindices: is an array of an int[4] per tessface, - * mapping tessface's verts to loops indices. - * - * \note when mface is not NULL, mface[face_index].v4 - * is used to test quads, else, loopindices[face_index][3] is used. - */ -static void mesh_loops_to_tessdata(CustomData *fdata, - CustomData *ldata, - MFace *mface, - const int *polyindices, - uint (*loopindices)[4], - const int num_faces) -{ - /* NOTE(mont29): performances are sub-optimal when we get a NULL #MFace, - * we could be ~25% quicker with dedicated code. - * The issue is, unless having two different functions with nearly the same code, - * there's not much ways to solve this. Better IMHO to live with it for now (sigh). */ - const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV); - const int numCol = CustomData_number_of_layers(ldata, CD_PROP_BYTE_COLOR); - const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL); - const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP); - const bool hasLoopNormal = CustomData_has_layer(ldata, CD_NORMAL); - const bool hasLoopTangent = CustomData_has_layer(ldata, CD_TANGENT); - int findex, i, j; - const int *pidx; - uint(*lidx)[4]; - - for (i = 0; i < numUV; i++) { - MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i); - const MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i); - - for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces; - pidx++, lidx++, findex++, texface++) { - for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) { - copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv); - } - } - } - - for (i = 0; i < numCol; i++) { - MCol(*mcol)[4] = CustomData_get_layer_n(fdata, CD_MCOL, i); - const MLoopCol *mloopcol = CustomData_get_layer_n(ldata, CD_PROP_BYTE_COLOR, i); - - for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) { - for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) { - MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]); - } - } - } - - if (hasPCol) { - MCol(*mcol)[4] = CustomData_get_layer(fdata, CD_PREVIEW_MCOL); - const MLoopCol *mloopcol = CustomData_get_layer(ldata, CD_PREVIEW_MLOOPCOL); - - for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) { - for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) { - MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]); - } - } - } - - if (hasOrigSpace) { - OrigSpaceFace *of = CustomData_get_layer(fdata, CD_ORIGSPACE); - const OrigSpaceLoop *lof = CustomData_get_layer(ldata, CD_ORIGSPACE_MLOOP); - - for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, of++) { - for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) { - copy_v2_v2(of->uv[j], lof[(*lidx)[j]].uv); - } - } - } - - if (hasLoopNormal) { - short(*fnors)[4][3] = CustomData_get_layer(fdata, CD_TESSLOOPNORMAL); - const float(*lnors)[3] = CustomData_get_layer(ldata, CD_NORMAL); - - for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, fnors++) { - for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) { - normal_float_to_short_v3((*fnors)[j], lnors[(*lidx)[j]]); - } - } - } - - if (hasLoopTangent) { - /* Need to do for all UV maps at some point. */ - float(*ftangents)[4] = CustomData_get_layer(fdata, CD_TANGENT); - const float(*ltangents)[4] = CustomData_get_layer(ldata, CD_TANGENT); - - for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces; - pidx++, lidx++, findex++) { - int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; - for (j = nverts; j--;) { - copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]); - } - } - } -} - -static int mesh_tessface_calc(CustomData *fdata, - CustomData *ldata, - CustomData *pdata, - MVert *mvert, - int totface, - int totloop, - int totpoly) -{ -#define USE_TESSFACE_SPEEDUP -#define USE_TESSFACE_QUADS - -/* We abuse #MFace.edcode to tag quad faces. See below for details. */ -#define TESSFACE_IS_QUAD 1 - - const int looptri_num = poly_to_tri_count(totpoly, totloop); - - const MPoly *mp, *mpoly; - const MLoop *ml, *mloop; - MFace *mface, *mf; - MemArena *arena = NULL; - int *mface_to_poly_map; - uint(*lindices)[4]; - int poly_index, mface_index; - uint j; - - mpoly = CustomData_get_layer(pdata, CD_MPOLY); - mloop = CustomData_get_layer(ldata, CD_MLOOP); - - /* Allocate the length of `totfaces`, avoid many small reallocation's, - * if all faces are triangles it will be correct, `quads == 2x` allocations. */ - /* Take care since memory is _not_ zeroed so be sure to initialize each field. */ - mface_to_poly_map = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface_to_poly_map), __func__); - mface = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface), __func__); - lindices = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*lindices), __func__); - - mface_index = 0; - mp = mpoly; - for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) { - const uint mp_loopstart = (uint)mp->loopstart; - const uint mp_totloop = (uint)mp->totloop; - uint l1, l2, l3, l4; - uint *lidx; - if (mp_totloop < 3) { - /* Do nothing. */ - } - -#ifdef USE_TESSFACE_SPEEDUP - -# define ML_TO_MF(i1, i2, i3) \ - mface_to_poly_map[mface_index] = poly_index; \ - mf = &mface[mface_index]; \ - lidx = lindices[mface_index]; \ - /* Set loop indices, transformed to vert indices later. */ \ - l1 = mp_loopstart + i1; \ - l2 = mp_loopstart + i2; \ - l3 = mp_loopstart + i3; \ - mf->v1 = mloop[l1].v; \ - mf->v2 = mloop[l2].v; \ - mf->v3 = mloop[l3].v; \ - mf->v4 = 0; \ - lidx[0] = l1; \ - lidx[1] = l2; \ - lidx[2] = l3; \ - lidx[3] = 0; \ - mf->mat_nr = mp->mat_nr; \ - mf->flag = mp->flag; \ - mf->edcode = 0; \ - (void)0 - -/* ALMOST IDENTICAL TO DEFINE ABOVE (see EXCEPTION) */ -# define ML_TO_MF_QUAD() \ - mface_to_poly_map[mface_index] = poly_index; \ - mf = &mface[mface_index]; \ - lidx = lindices[mface_index]; \ - /* Set loop indices, transformed to vert indices later. */ \ - l1 = mp_loopstart + 0; /* EXCEPTION */ \ - l2 = mp_loopstart + 1; /* EXCEPTION */ \ - l3 = mp_loopstart + 2; /* EXCEPTION */ \ - l4 = mp_loopstart + 3; /* EXCEPTION */ \ - mf->v1 = mloop[l1].v; \ - mf->v2 = mloop[l2].v; \ - mf->v3 = mloop[l3].v; \ - mf->v4 = mloop[l4].v; \ - lidx[0] = l1; \ - lidx[1] = l2; \ - lidx[2] = l3; \ - lidx[3] = l4; \ - mf->mat_nr = mp->mat_nr; \ - mf->flag = mp->flag; \ - mf->edcode = TESSFACE_IS_QUAD; \ - (void)0 - - else if (mp_totloop == 3) { - ML_TO_MF(0, 1, 2); - mface_index++; - } - else if (mp_totloop == 4) { -# ifdef USE_TESSFACE_QUADS - ML_TO_MF_QUAD(); - mface_index++; -# else - ML_TO_MF(0, 1, 2); - mface_index++; - ML_TO_MF(0, 2, 3); - mface_index++; -# endif - } -#endif /* USE_TESSFACE_SPEEDUP */ - else { - const float *co_curr, *co_prev; - - float normal[3]; - - float axis_mat[3][3]; - float(*projverts)[2]; - uint(*tris)[3]; - - const uint totfilltri = mp_totloop - 2; - - if (UNLIKELY(arena == NULL)) { - arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - } - - tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri); - projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop); - - zero_v3(normal); - - /* Calculate the normal, flipped: to get a positive 2D cross product. */ - ml = mloop + mp_loopstart; - co_prev = mvert[ml[mp_totloop - 1].v].co; - for (j = 0; j < mp_totloop; j++, ml++) { - co_curr = mvert[ml->v].co; - add_newell_cross_v3_v3v3(normal, co_prev, co_curr); - co_prev = co_curr; - } - if (UNLIKELY(normalize_v3(normal) == 0.0f)) { - normal[2] = 1.0f; - } - - /* Project verts to 2D. */ - axis_dominant_v3_to_m3_negate(axis_mat, normal); - - ml = mloop + mp_loopstart; - for (j = 0; j < mp_totloop; j++, ml++) { - mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co); - } - - BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena); - - /* Apply fill. */ - for (j = 0; j < totfilltri; j++) { - uint *tri = tris[j]; - lidx = lindices[mface_index]; - - mface_to_poly_map[mface_index] = poly_index; - mf = &mface[mface_index]; - - /* Set loop indices, transformed to vert indices later. */ - l1 = mp_loopstart + tri[0]; - l2 = mp_loopstart + tri[1]; - l3 = mp_loopstart + tri[2]; - - mf->v1 = mloop[l1].v; - mf->v2 = mloop[l2].v; - mf->v3 = mloop[l3].v; - mf->v4 = 0; - - lidx[0] = l1; - lidx[1] = l2; - lidx[2] = l3; - lidx[3] = 0; - - mf->mat_nr = mp->mat_nr; - mf->flag = mp->flag; - mf->edcode = 0; - - mface_index++; - } - - BLI_memarena_clear(arena); - } - } - - if (arena) { - BLI_memarena_free(arena); - arena = NULL; - } - - CustomData_free(fdata, totface); - totface = mface_index; - - BLI_assert(totface <= looptri_num); - - /* Not essential but without this we store over-allocated memory in the #CustomData layers. */ - if (LIKELY(looptri_num != totface)) { - mface = MEM_reallocN(mface, sizeof(*mface) * (size_t)totface); - mface_to_poly_map = MEM_reallocN(mface_to_poly_map, - sizeof(*mface_to_poly_map) * (size_t)totface); - } - - CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface); - - /* #CD_ORIGINDEX will contain an array of indices from tessellation-faces to the polygons - * they are directly tessellated from. */ - CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface); - CustomData_from_bmeshpoly(fdata, ldata, totface); - - /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx: - * Polygons take care of their loops ordering, hence not of their vertices ordering. - * Currently, our tfaces' fourth vertex index might be 0 even for a quad. - * However, we know our fourth loop index is never 0 for quads - * (because they are sorted for polygons, and our quads are still mere copies of their polygons). - * So we pass NULL as MFace pointer, and #mesh_loops_to_tessdata - * will use the fourth loop index as quad test. */ - mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface); - - /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx: - * ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad. - * BKE_mesh_mface_index_validate() will check this and rotate the tessellated face if needed. - */ -#ifdef USE_TESSFACE_QUADS - mf = mface; - for (mface_index = 0; mface_index < totface; mface_index++, mf++) { - if (mf->edcode == TESSFACE_IS_QUAD) { - BKE_mesh_mface_index_validate(mf, fdata, mface_index, 4); - mf->edcode = 0; - } - } -#endif - - MEM_freeN(lindices); - - return totface; - -#undef USE_TESSFACE_SPEEDUP -#undef USE_TESSFACE_QUADS - -#undef ML_TO_MF -#undef ML_TO_MF_QUAD -} - -void BKE_mesh_tessface_calc(Mesh *mesh) -{ - mesh->totface = mesh_tessface_calc(&mesh->fdata, - &mesh->ldata, - &mesh->pdata, - mesh->mvert, - mesh->totface, - mesh->totloop, - mesh->totpoly); - - BKE_mesh_update_customdata_pointers(mesh, true); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Loop Tessellation * * Fill in #MLoopTri data-structure. diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index b44b70bcd55..b5ff12f3caa 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -64,6 +64,7 @@ #include "BKE_pointcache.h" #include "BKE_scene.h" #include "BKE_texture.h" +#include "BKE_mesh_legacy_convert.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index c461b7f108d..da769515f08 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -28,6 +28,7 @@ #include "BKE_global.h" #include "BKE_lib_id.h" #include "BKE_mesh.h" +#include "BKE_mesh_legacy_convert.h" #include "BKE_object.h" #include "BKE_particle.h" diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 3ad770c5429..4a8f029beee 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -47,6 +47,7 @@ #include "BKE_effect.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" +#include "BKE_mesh_legacy_convert.h" #include "BKE_particle.h" #include "BKE_bvhutils.h" diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 426008e887e..82e24801b66 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -73,6 +73,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_legacy_convert.h" #include "BKE_node.h" #include "BKE_node_tree_update.h" #include "BKE_paint.h" diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index c1d609bf648..16201e809c7 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -26,6 +26,7 @@ #include "BKE_mesh.h" #include "BKE_particle.h" #include "BKE_pointcache.h" +#include "BKE_mesh_legacy_convert.h" #include "ED_particle.h" diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc index a6ae1ba5e24..cffa590470f 100644 --- a/source/blender/editors/curves/intern/curves_ops.cc +++ b/source/blender/editors/curves/intern/curves_ops.cc @@ -25,6 +25,7 @@ #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_mesh.h" +#include "BKE_mesh_legacy_convert.h" #include "BKE_mesh_runtime.h" #include "BKE_object.h" #include "BKE_paint.h" diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 64d5ee91215..03f9b4eb867 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -32,6 +32,7 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_legacy_convert.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_object.h" diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 6bea6e2c19e..96aea0ededf 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -26,6 +26,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_legacy_convert.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_object.h" diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.cc b/source/blender/io/alembic/exporter/abc_writer_hair.cc index d12eaf07e29..99c609b0235 100644 --- a/source/blender/io/alembic/exporter/abc_writer_hair.cc +++ b/source/blender/io/alembic/exporter/abc_writer_hair.cc @@ -18,6 +18,7 @@ #include "BKE_customdata.h" #include "BKE_mesh.h" +#include "BKE_mesh_legacy_convert.h" #include "BKE_mesh_runtime.h" #include "BKE_particle.h" diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp index 0c902700b6b..75842734b08 100644 --- a/source/blender/io/collada/collada_utils.cpp +++ b/source/blender/io/collada/collada_utils.cpp @@ -40,6 +40,7 @@ #include "BKE_lib_id.h" #include "BKE_material.h" #include "BKE_mesh.h" +#include "BKE_mesh_legacy_convert.h" #include "BKE_mesh_runtime.h" #include "BKE_node.h" #include "BKE_object.h" diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index a67b0f7c8e6..3fc98d769b6 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -25,6 +25,7 @@ #include "RNA_enum_types.h" #include "BKE_mesh.h" +#include "BKE_mesh_legacy_convert.h" #include "BLI_listbase.h" diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index 8e85cb1bfb3..f88e930e127 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -26,6 +26,7 @@ #include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_mesh.h" +#include "BKE_mesh_legacy_convert.h" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_scene.h" diff --git a/source/blender/modifiers/intern/MOD_particlesystem.cc b/source/blender/modifiers/intern/MOD_particlesystem.cc index f410915cad8..ccbc8f1d835 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.cc +++ b/source/blender/modifiers/intern/MOD_particlesystem.cc @@ -21,6 +21,7 @@ #include "BKE_editmesh.h" #include "BKE_lib_id.h" #include "BKE_mesh.h" +#include "BKE_mesh_legacy_convert.h" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_screen.h" |