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:
Diffstat (limited to 'source/blender/blenkernel/intern/mesh.c')
-rw-r--r--source/blender/blenkernel/intern/mesh.c446
1 files changed, 317 insertions, 129 deletions
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index d21f43ac484..0d01fe77453 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -39,7 +39,9 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_linklist.h"
#include "BLI_listbase.h"
+#include "BLI_memarena.h"
#include "BLI_edgehash.h"
#include "BLI_string.h"
@@ -66,6 +68,11 @@
#include "DEG_depsgraph.h"
+/* Define for cases when you want extra validation of mesh
+ * after certain modifications.
+ */
+// #undef VALIDATE_MESH
+
enum {
MESHCMP_DVERT_WEIGHTMISMATCH = 1,
MESHCMP_DVERT_GROUPMISMATCH,
@@ -487,53 +494,56 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name)
{
Mesh *me;
- me = BKE_libblock_alloc(bmain, ID_ME, name);
+ me = BKE_libblock_alloc(bmain, ID_ME, name, 0);
BKE_mesh_init(me);
return me;
}
-Mesh *BKE_mesh_copy(Main *bmain, Mesh *me)
+/**
+ * Only copy internal data of Mesh ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int flag)
{
- Mesh *men;
- int a;
- const int do_tessface = ((me->totface != 0) && (me->totpoly == 0)); /* only do tessface if we have no polys */
-
- men = BKE_libblock_copy(bmain, &me->id);
-
- men->mat = MEM_dupallocN(me->mat);
- for (a = 0; a < men->totcol; a++) {
- id_us_plus((ID *)men->mat[a]);
- }
- id_us_plus((ID *)men->texcomesh);
+ const bool do_tessface = ((me_src->totface != 0) && (me_src->totpoly == 0)); /* only do tessface if we have no polys */
+
+ me_dst->mat = MEM_dupallocN(me_src->mat);
- CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert);
- CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge);
- CustomData_copy(&me->ldata, &men->ldata, CD_MASK_MESH, CD_DUPLICATE, men->totloop);
- CustomData_copy(&me->pdata, &men->pdata, CD_MASK_MESH, CD_DUPLICATE, men->totpoly);
+ CustomData_copy(&me_src->vdata, &me_dst->vdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totvert);
+ CustomData_copy(&me_src->edata, &me_dst->edata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totedge);
+ CustomData_copy(&me_src->ldata, &me_dst->ldata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totloop);
+ CustomData_copy(&me_src->pdata, &me_dst->pdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totpoly);
if (do_tessface) {
- CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface);
+ CustomData_copy(&me_src->fdata, &me_dst->fdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totface);
}
else {
- mesh_tessface_clear_intern(men, false);
+ mesh_tessface_clear_intern(me_dst, false);
}
- BKE_mesh_update_customdata_pointers(men, do_tessface);
+ BKE_mesh_update_customdata_pointers(me_dst, do_tessface);
- men->edit_btmesh = NULL;
+ me_dst->edit_btmesh = NULL;
- men->mselect = MEM_dupallocN(men->mselect);
- men->bb = MEM_dupallocN(men->bb);
+ me_dst->mselect = MEM_dupallocN(me_dst->mselect);
+ me_dst->bb = MEM_dupallocN(me_dst->bb);
- if (me->key) {
- men->key = BKE_key_copy(bmain, me->key);
- men->key->from = (ID *)men;
+ /* TODO Do we want to add flag to prevent this? */
+ if (me_src->key) {
+ BKE_id_copy_ex(bmain, &me_src->key->id, (ID **)&me_dst->key, flag, false);
}
+}
- BKE_id_copy_ensure_local(bmain, &me->id, &men->id);
-
- return men;
+Mesh *BKE_mesh_copy(Main *bmain, const Mesh *me)
+{
+ Mesh *me_copy;
+ BKE_id_copy_ex(bmain, &me->id, (ID **)&me_copy, 0, false);
+ return me_copy;
}
BMesh *BKE_mesh_to_bmesh(
@@ -1332,7 +1342,7 @@ int BKE_mesh_nurbs_displist_to_mdata(
/* this may fail replacing ob->data, be sure to check ob->type */
-void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use_orco_uv)
+void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name)
{
Main *bmain = G.main;
Object *ob1;
@@ -1359,7 +1369,7 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
}
/* make mesh */
- me = BKE_mesh_add(bmain, "Mesh");
+ me = BKE_mesh_add(bmain, obdata_name);
me->totvert = totvert;
me->totedge = totedge;
me->totloop = totloop;
@@ -1379,7 +1389,7 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
BKE_mesh_calc_normals(me);
}
else {
- me = BKE_mesh_add(bmain, "Mesh");
+ me = BKE_mesh_add(bmain, obdata_name);
DM_to_mesh(dm, me, ob, CD_MASK_MESH, false);
}
@@ -1391,9 +1401,7 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
cu->mat = NULL;
cu->totcol = 0;
- if (ob->data) {
- BKE_libblock_free(bmain, ob->data);
- }
+ /* Do not decrement ob->data usercount here, it's done at end of func with BKE_libblock_free_us() call. */
ob->data = me;
ob->type = OB_MESH;
@@ -1403,11 +1411,14 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
if (ob1->data == cu) {
ob1->type = OB_MESH;
+ id_us_min((ID *)ob1->data);
ob1->data = ob->data;
- id_us_plus((ID *)ob->data);
+ id_us_plus((ID *)ob1->data);
}
ob1 = ob1->id.next;
}
+
+ BKE_libblock_free_us(bmain, cu);
}
void BKE_mesh_from_nurbs(Object *ob)
@@ -1420,7 +1431,7 @@ void BKE_mesh_from_nurbs(Object *ob)
disp = ob->curve_cache->disp;
}
- BKE_mesh_from_nurbs_displist(ob, &disp, use_orco_uv);
+ BKE_mesh_from_nurbs_displist(ob, &disp, use_orco_uv, cu->id.name);
}
typedef struct EdgeLink {
@@ -2048,13 +2059,24 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
(me->mselect[me->totselect - 1].type == type));
}
-void BKE_mesh_calc_normals_split(Mesh *mesh)
+/**
+ * Compute 'split' (aka loop, or per face corner's) normals.
+ *
+ * \param r_lnors_spacearr Allows to get computed loop normal space array. That data, among other things,
+ * contains 'smooth fan' info, useful e.g. to split geometry along sharp edges...
+ */
+void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
{
float (*r_loopnors)[3];
float (*polynors)[3];
short (*clnors)[2] = NULL;
bool free_polynors = false;
+ /* Note that we enforce computing clnors when the clnor space array is requested by caller here.
+ * However, we obviously only use the autosmooth angle threshold only in case autosmooth is enabled. */
+ const bool use_split_normals = (r_lnors_spacearr != NULL) || ((mesh->flag & ME_AUTOSMOOTH) != 0);
+ const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI;
+
if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop);
@@ -2083,113 +2105,272 @@ void BKE_mesh_calc_normals_split(Mesh *mesh)
BKE_mesh_normals_loop_split(
mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge,
mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly,
- (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, NULL, clnors, NULL);
+ use_split_normals, split_angle, r_lnors_spacearr, clnors, NULL);
if (free_polynors) {
MEM_freeN(polynors);
}
}
-/* Spli faces based on the edge angle.
- * Matches behavior of face splitting in render engines.
- */
-void BKE_mesh_split_faces(Mesh *mesh)
+void BKE_mesh_calc_normals_split(Mesh *mesh)
{
- const int num_verts = mesh->totvert;
- const int num_edges = mesh->totedge;
- const int num_polys = mesh->totpoly;
+ BKE_mesh_calc_normals_split_ex(mesh, NULL);
+}
+
+/* Split faces helper functions. */
+
+typedef struct SplitFaceNewVert {
+ struct SplitFaceNewVert *next;
+ int new_index;
+ int orig_index;
+ float *vnor;
+} SplitFaceNewVert;
+
+typedef struct SplitFaceNewEdge {
+ struct SplitFaceNewEdge *next;
+ int new_index;
+ int orig_index;
+ int v1;
+ int v2;
+} SplitFaceNewEdge;
+
+/* Detect needed new vertices, and update accordingly loops' vertex indices.
+ * WARNING! Leaves mesh in invalid state. */
+static int split_faces_prepare_new_verts(
+ const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert **new_verts, MemArena *memarena)
+{
+ /* This is now mandatory, trying to do the job in simple way without that data is doomed to fail, even when only
+ * dealing with smooth/flat faces one can find cases that no simple algorithm can handle properly. */
+ BLI_assert(lnors_spacearr != NULL);
+
+ const int num_loops = mesh->totloop;
+ int num_verts = mesh->totvert;
MVert *mvert = mesh->mvert;
- MEdge *medge = mesh->medge;
MLoop *mloop = mesh->mloop;
- MPoly *mpoly = mesh->mpoly;
- float (*lnors)[3];
- int poly, num_new_verts = 0;
- if ((mesh->flag & ME_AUTOSMOOTH) == 0) {
- return;
- }
- BKE_mesh_tessface_clear(mesh);
- /* Compute loop normals if needed. */
- if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
- BKE_mesh_calc_normals_split(mesh);
- }
- lnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
- /* Count number of vertices to be split. */
- for (poly = 0; poly < num_polys; poly++) {
- MPoly *mp = &mpoly[poly];
- int loop;
- for (loop = 0; loop < mp->totloop; loop++) {
- MLoop *ml = &mloop[mp->loopstart + loop];
- MVert *mv = &mvert[ml->v];
- float vn[3];
- normal_short_to_float_v3(vn, mv->no);
- if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) {
- num_new_verts++;
+
+ BLI_bitmap *verts_used = BLI_BITMAP_NEW(num_verts, __func__);
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__);
+
+ MLoop *ml = mloop;
+ MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
+
+ for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) {
+ if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
+ const int vert_idx = ml->v;
+ const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx);
+ /* If vert is already used by another smooth fan, we need a new vert for this one. */
+ const int new_vert_idx = vert_used ? num_verts++ : vert_idx;
+
+ BLI_assert(*lnor_space);
+
+ if ((*lnor_space)->loops) {
+ for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) {
+ const int ml_fan_idx = GET_INT_FROM_POINTER(lnode->link);
+ BLI_BITMAP_ENABLE(done_loops, ml_fan_idx);
+ if (vert_used) {
+ mloop[ml_fan_idx].v = new_vert_idx;
+ }
+ }
+ }
+ else {
+ /* Single loop in this fan... */
+ BLI_BITMAP_ENABLE(done_loops, loop_idx);
+ if (vert_used) {
+ ml->v = new_vert_idx;
+ }
+ }
+
+ if (!vert_used) {
+ BLI_BITMAP_ENABLE(verts_used, vert_idx);
+ /* We need to update that vertex's normal here, we won't go over it again. */
+ /* This is important! *DO NOT* set vnor to final computed lnor, vnor should always be defined to
+ * 'automatic normal' value computed from its polys, not some custom normal.
+ * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
+ normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor);
+ }
+ else {
+ /* Add new vert to list. */
+ SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert));
+ new_vert->orig_index = vert_idx;
+ new_vert->new_index = new_vert_idx;
+ new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */
+ new_vert->next = *new_verts;
+ *new_verts = new_vert;
}
}
}
- if (num_new_verts == 0) {
- /* No new vertices are to be added, can do early exit. */
- return;
- }
- /* Reallocate all vert and edge related data. */
- mesh->totvert += num_new_verts;
- mesh->totedge += 2 * num_new_verts;
- CustomData_realloc(&mesh->vdata, mesh->totvert);
- CustomData_realloc(&mesh->edata, mesh->totedge);
- /* Update pointers to a newly allocated memory. */
- BKE_mesh_update_customdata_pointers(mesh, false);
- mvert = mesh->mvert;
- medge = mesh->medge;
- /* Perform actual vertex split. */
- num_new_verts = 0;
- for (poly = 0; poly < num_polys; poly++) {
- MPoly *mp = &mpoly[poly];
- int loop;
- for (loop = 0; loop < mp->totloop; loop++) {
- int poly_loop = mp->loopstart + loop;
- MLoop *ml = &mloop[poly_loop];
- MVert *mv = &mvert[ml->v];
- float vn[3];
- normal_short_to_float_v3(vn, mv->no);
- if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) {
- int poly_loop_prev = mp->loopstart + (loop + mp->totloop - 1) % mp->totloop;
- MLoop *ml_prev = &mloop[poly_loop_prev];
- int new_edge_prev, new_edge;
- /* Cretae new vertex. */
- int new_vert = num_verts + num_new_verts;
- CustomData_copy_data(&mesh->vdata, &mesh->vdata,
- ml->v, new_vert, 1);
- normal_float_to_short_v3(mvert[new_vert].no,
- lnors[poly_loop]);
- /* Create new edges. */
- new_edge_prev = num_edges + 2 * num_new_verts;
- new_edge = num_edges + 2 * num_new_verts + 1;
- CustomData_copy_data(&mesh->edata, &mesh->edata,
- ml_prev->e, new_edge_prev, 1);
- CustomData_copy_data(&mesh->edata, &mesh->edata,
- ml->e, new_edge, 1);
- if (medge[new_edge_prev].v1 == ml->v) {
- medge[new_edge_prev].v1 = new_vert;
- }
- else {
- medge[new_edge_prev].v2 = new_vert;
- }
- if (medge[new_edge].v1 == ml->v) {
- medge[new_edge].v1 = new_vert;
+
+ MEM_freeN(done_loops);
+ MEM_freeN(verts_used);
+
+ return num_verts - mesh->totvert;
+}
+
+/* Detect needed new edges, and update accordingly loops' edge indices.
+ * WARNING! Leaves mesh in invalid state. */
+static int split_faces_prepare_new_edges(
+ const Mesh *mesh, SplitFaceNewEdge **new_edges, MemArena *memarena)
+{
+ const int num_polys = mesh->totpoly;
+ int num_edges = mesh->totedge;
+ MEdge *medge = mesh->medge;
+ MLoop *mloop = mesh->mloop;
+ const MPoly *mpoly = mesh->mpoly;
+
+ BLI_bitmap *edges_used = BLI_BITMAP_NEW(num_edges, __func__);
+ EdgeHash *edges_hash = BLI_edgehash_new_ex(__func__, num_edges);
+
+ const MPoly *mp = mpoly;
+ for (int poly_idx = 0; poly_idx < num_polys; poly_idx++, mp++) {
+ MLoop *ml_prev = &mloop[mp->loopstart + mp->totloop - 1];
+ MLoop *ml = &mloop[mp->loopstart];
+ for (int loop_idx = 0; loop_idx < mp->totloop; loop_idx++, ml++) {
+ void **eval;
+ if (!BLI_edgehash_ensure_p(edges_hash, ml_prev->v, ml->v, &eval)) {
+ const int edge_idx = ml_prev->e;
+
+ /* That edge has not been encountered yet, define it. */
+ if (BLI_BITMAP_TEST(edges_used, edge_idx)) {
+ /* Original edge has already been used, we need to define a new one. */
+ const int new_edge_idx = num_edges++;
+ *eval = SET_INT_IN_POINTER(new_edge_idx);
+ ml_prev->e = new_edge_idx;
+
+ SplitFaceNewEdge *new_edge = BLI_memarena_alloc(memarena, sizeof(*new_edge));
+ new_edge->orig_index = edge_idx;
+ new_edge->new_index = new_edge_idx;
+ new_edge->v1 = ml_prev->v;
+ new_edge->v2 = ml->v;
+ new_edge->next = *new_edges;
+ *new_edges = new_edge;
}
else {
- medge[new_edge].v2 = new_vert;
+ /* We can re-use original edge. */
+ medge[edge_idx].v1 = ml_prev->v;
+ medge[edge_idx].v2 = ml->v;
+ *eval = SET_INT_IN_POINTER(edge_idx);
+ BLI_BITMAP_ENABLE(edges_used, edge_idx);
}
-
- ml->v = new_vert;
- ml_prev->e = new_edge_prev;
- ml->e = new_edge;
- num_new_verts++;
}
+ else {
+ /* Edge already known, just update loop's edge index. */
+ ml_prev->e = GET_INT_FROM_POINTER(*eval);
+ }
+
+ ml_prev = ml;
+ }
+ }
+
+ MEM_freeN(edges_used);
+ BLI_edgehash_free(edges_hash, NULL);
+
+ return num_edges - mesh->totedge;
+}
+
+/* Perform actual split of vertices. */
+static void split_faces_split_new_verts(
+ Mesh *mesh, SplitFaceNewVert *new_verts, const int num_new_verts)
+{
+ const int num_verts = mesh->totvert - num_new_verts;
+ MVert *mvert = mesh->mvert;
+
+ /* Remember new_verts is a single linklist, so its items are in reversed order... */
+ MVert *new_mv = &mvert[mesh->totvert - 1];
+ for (int i = mesh->totvert - 1; i >= num_verts ; i--, new_mv--, new_verts = new_verts->next) {
+ BLI_assert(new_verts->new_index == i);
+ BLI_assert(new_verts->new_index != new_verts->orig_index);
+ CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
+ if (new_verts->vnor) {
+ normal_float_to_short_v3(new_mv->no, new_verts->vnor);
}
}
}
+/* Perform actual split of edges. */
+static void split_faces_split_new_edges(
+ Mesh *mesh, SplitFaceNewEdge *new_edges, const int num_new_edges)
+{
+ const int num_edges = mesh->totedge - num_new_edges;
+ MEdge *medge = mesh->medge;
+
+ /* Remember new_edges is a single linklist, so its items are in reversed order... */
+ MEdge *new_med = &medge[mesh->totedge - 1];
+ for (int i = mesh->totedge - 1; i >= num_edges ; i--, new_med--, new_edges = new_edges->next) {
+ BLI_assert(new_edges->new_index == i);
+ BLI_assert(new_edges->new_index != new_edges->orig_index);
+ CustomData_copy_data(&mesh->edata, &mesh->edata, new_edges->orig_index, i, 1);
+ new_med->v1 = new_edges->v1;
+ new_med->v2 = new_edges->v2;
+ }
+}
+
+/* Split faces based on the edge angle and loop normals.
+ * Matches behavior of face splitting in render engines.
+ *
+ * NOTE: Will leave CD_NORMAL loop data layer which is
+ * used by render engines to set shading up.
+ */
+void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
+{
+ const int num_polys = mesh->totpoly;
+
+ if (num_polys == 0) {
+ return;
+ }
+ BKE_mesh_tessface_clear(mesh);
+
+ MLoopNorSpaceArray lnors_spacearr = {NULL};
+ /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */
+ BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr);
+ /* Stealing memarena from loop normals space array. */
+ MemArena *memarena = lnors_spacearr.mem;
+
+ SplitFaceNewVert *new_verts = NULL;
+ SplitFaceNewEdge *new_edges = NULL;
+
+ /* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */
+ const int num_new_verts = split_faces_prepare_new_verts(mesh, &lnors_spacearr, &new_verts, memarena);
+
+ if (num_new_verts > 0) {
+ /* Reminder: beyond this point, there is no way out, mesh is in invalid state (due to early-reassignment of
+ * loops' vertex and edge indices to new, to-be-created split ones). */
+
+ const int num_new_edges = split_faces_prepare_new_edges(mesh, &new_edges, memarena);
+ /* We can have to split a vertex without having to add a single new edge... */
+ const bool do_edges = (num_new_edges > 0);
+
+ /* Reallocate all vert and edge related data. */
+ mesh->totvert += num_new_verts;
+ CustomData_realloc(&mesh->vdata, mesh->totvert);
+ if (do_edges) {
+ mesh->totedge += num_new_edges;
+ CustomData_realloc(&mesh->edata, mesh->totedge);
+ }
+ /* Update pointers to a newly allocated memory. */
+ BKE_mesh_update_customdata_pointers(mesh, false);
+
+ /* Perform actual split of vertices and edges. */
+ split_faces_split_new_verts(mesh, new_verts, num_new_verts);
+ if (do_edges) {
+ split_faces_split_new_edges(mesh, new_edges, num_new_edges);
+ }
+ }
+
+ /* Note: after this point mesh is expected to be valid again. */
+
+ /* CD_NORMAL is expected to be temporary only. */
+ if (free_loop_normals) {
+ CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop);
+ }
+
+ /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */
+ BKE_lnor_spacearr_free(&lnors_spacearr);
+
+#ifdef VALIDATE_MESH
+ BKE_mesh_validate(mesh, true, true);
+#endif
+}
+
/* settings: 1 - preview, 2 - render */
Mesh *BKE_mesh_new_from_object(
Main *bmain, Scene *sce, Object *ob,
@@ -2213,7 +2394,9 @@ Mesh *BKE_mesh_new_from_object(
int uv_from_orco;
/* copies object and modifiers (but not the data) */
- Object *tmpobj = BKE_object_copy_ex(bmain, ob, true);
+ Object *tmpobj;
+ /* TODO: make it temp copy outside bmain! */
+ BKE_id_copy_ex(bmain, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_CACHES, false);
tmpcu = (Curve *)tmpobj->data;
id_us_min(&tmpcu->id);
@@ -2253,7 +2436,7 @@ Mesh *BKE_mesh_new_from_object(
/* convert object type to mesh */
uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0;
- BKE_mesh_from_nurbs_displist(tmpobj, &dispbase, uv_from_orco);
+ BKE_mesh_from_nurbs_displist(tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2);
tmpmesh = tmpobj->data;
@@ -2289,7 +2472,7 @@ Mesh *BKE_mesh_new_from_object(
if (ob != basis_ob)
return NULL; /* only do basis metaball */
- tmpmesh = BKE_mesh_add(bmain, "Mesh");
+ tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2);
/* BKE_mesh_add gives us a user count we don't need */
id_us_min(&tmpmesh->id);
@@ -2344,8 +2527,13 @@ Mesh *BKE_mesh_new_from_object(
else
dm = mesh_create_derived_view(sce, ob, mask);
- tmpmesh = BKE_mesh_add(bmain, "Mesh");
+ tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2);
DM_to_mesh(dm, tmpmesh, ob, mask, true);
+
+ /* Copy autosmooth settings from original mesh. */
+ Mesh *me = (Mesh *)ob->data;
+ tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH);
+ tmpmesh->smoothresh = me->smoothresh;
}
/* BKE_mesh_add/copy gives us a user count we don't need */