Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_customdata.h24
-rw-r--r--source/blender/blenkernel/BKE_mesh.h61
-rw-r--r--source/blender/blenkernel/BKE_mesh_legacy_convert.h73
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/customdata.cc122
-rw-r--r--source/blender/blenkernel/intern/mesh.cc78
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.cc272
-rw-r--r--source/blender/blenkernel/intern/mesh_legacy_convert.cc876
-rw-r--r--source/blender/blenkernel/intern/mesh_tessellate.c364
-rw-r--r--source/blender/blenkernel/intern/particle.c1
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c1
-rw-r--r--source/blender/blenkernel/intern/particle_system.c1
-rw-r--r--source/blender/blenloader/intern/versioning_280.c1
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c1
-rw-r--r--source/blender/editors/curves/intern/curves_ops.cc1
-rw-r--r--source/blender/editors/physics/particle_edit.c1
-rw-r--r--source/blender/editors/physics/particle_object.c1
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_hair.cc1
-rw-r--r--source/blender/io/collada/collada_utils.cpp1
-rw-r--r--source/blender/makesrna/intern/rna_particle.c1
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c1
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.cc1
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"