diff options
Diffstat (limited to 'source/blender/blenkernel/intern/mesh.c')
-rw-r--r-- | source/blender/blenkernel/intern/mesh.c | 285 |
1 files changed, 271 insertions, 14 deletions
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 419f907d786..c8223657a05 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -61,6 +61,7 @@ #include "BKE_object.h" #include "BKE_editmesh.h" +#include "DEG_depsgraph.h" enum { MESHCMP_DVERT_WEIGHTMISMATCH = 1, @@ -463,7 +464,7 @@ void BKE_mesh_free(Mesh *me, int unlink) CustomData_free(&me->pdata, me->totpoly); if (me->adt) { - BKE_free_animdata(&me->id); + BKE_animdata_free(&me->id); me->adt = NULL; } @@ -1265,7 +1266,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase, dl = dispbase->first; while (dl) { - int smooth = dl->rt & CU_SMOOTH ? 1 : 0; + const bool is_smooth = (dl->rt & CU_SMOOTH) != 0; if (dl->type == DL_SEGM) { startvert = vertcount; @@ -1344,7 +1345,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase, } } - if (smooth) mpoly->flag |= ME_SMOOTH; + if (is_smooth) mpoly->flag |= ME_SMOOTH; mpoly++; mloop += 3; index += 3; @@ -1423,7 +1424,7 @@ int BKE_mesh_nurbs_displist_to_mdata(Object *ob, ListBase *dispbase, } } - if (smooth) mpoly->flag |= ME_SMOOTH; + if (is_smooth) mpoly->flag |= ME_SMOOTH; mpoly++; mloop += 4; @@ -1773,6 +1774,36 @@ void BKE_mesh_material_index_clear(Mesh *me) } } +void BKE_mesh_material_remap(Mesh *me, const unsigned int *remap, unsigned int remap_len) +{ + const short remap_len_short = (short)remap_len; + +#define MAT_NR_REMAP(n) \ + if (n < remap_len_short) { \ + BLI_assert(n >= 0 && remap[n] < remap_len_short); \ + n = remap[n]; \ + } ((void)0) + + if (me->edit_btmesh) { + BMEditMesh *em = me->edit_btmesh; + BMIter iter; + BMFace *efa; + + BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) { + MAT_NR_REMAP(efa->mat_nr); + } + } + else { + int i; + for (i = 0; i < me->totpoly; i++) { + MAT_NR_REMAP(me->mpoly[i].mat_nr); + } + } + +#undef MAT_NR_REMAP + +} + void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth) { Mesh *me = meshOb->data; @@ -1805,7 +1836,7 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth) * Return a newly MEM_malloc'd array of all the mesh vertex locations * \note \a r_numVerts may be NULL */ -float (*BKE_mesh_vertexCos_get(Mesh *me, int *r_numVerts))[3] +float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_numVerts))[3] { int i, numVerts = me->totvert; float (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "vertexcos1"); @@ -1821,8 +1852,9 @@ float (*BKE_mesh_vertexCos_get(Mesh *me, int *r_numVerts))[3] * Find the index of the loop in 'poly' which references vertex, * returns -1 if not found */ -int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, - unsigned vert) +int poly_find_loop_from_vert( + const MPoly *poly, const MLoop *loopstart, + unsigned vert) { int j; for (j = 0; j < poly->totloop; j++, loopstart++) { @@ -1838,20 +1870,22 @@ int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, * vertex. Returns the index of the loop matching vertex, or -1 if the * vertex is not in \a poly */ -int poly_get_adj_loops_from_vert(unsigned r_adj[3], const MPoly *poly, - const MLoop *mloop, unsigned vert) +int poly_get_adj_loops_from_vert( + unsigned r_adj[2], const MPoly *poly, + const MLoop *mloop, unsigned vert) { int corner = poly_find_loop_from_vert(poly, &mloop[poly->loopstart], vert); if (corner != -1) { +#if 0 /* unused - this loop */ const MLoop *ml = &mloop[poly->loopstart + corner]; +#endif /* vertex was found */ r_adj[0] = ME_POLY_LOOP_PREV(mloop, poly, corner)->v; - r_adj[1] = ml->v; - r_adj[2] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v; + r_adj[1] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v; } return corner; @@ -1887,6 +1921,7 @@ void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys) { int i; MVert *mvert = me->mvert; + float (*lnors)[3] = CustomData_get_layer(&me->ldata, CD_NORMAL); for (i = 0; i < me->totvert; i++, mvert++) mul_m4_v3(mat, mvert->co); @@ -1901,7 +1936,17 @@ void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys) } } - /* don't update normals, caller can do this explicitly */ + /* don't update normals, caller can do this explicitly. + * We do update loop normals though, those may not be auto-generated (see e.g. STL import script)! */ + if (lnors) { + float m3[3][3]; + + copy_m3_m4(m3, mat); + normalize_m3(m3); + for (i = 0; i < me->totloop; i++, lnors++) { + mul_m3_v3(m3, *lnors); + } + } } void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) @@ -2124,6 +2169,146 @@ 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) +{ + float (*r_loopnors)[3]; + float (*polynors)[3]; + short (*clnors)[2] = NULL; + bool free_polynors = false; + + 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); + } + else { + r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop); + CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); + } + + /* may be NULL */ + clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); + + if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { + /* This assume that layer is always up to date, not sure this is the case (esp. in Edit mode?)... */ + polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL); + free_polynors = false; + } + else { + polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__); + BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, + polynors, false); + free_polynors = true; + } + + 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); + + 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) +{ + const int num_verts = mesh->totvert; + const int num_edges = mesh->totedge; + const int num_polys = mesh->totpoly; + 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. */ + 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++; + } + } + } + if (num_new_verts == 0) { + /* No new vertices are to be added, can do early exit. */ + return; + } + /* Actual split. */ + mesh->totvert += num_new_verts; + mesh->totedge += 2 * num_new_verts; + mvert = mesh->mvert = MEM_reallocN(mesh->mvert, + sizeof(MVert) * mesh->totvert); + medge = mesh->medge = MEM_reallocN(mesh->medge, + sizeof(MEdge) * mesh->totedge); + CustomData_set_layer(&mesh->vdata, CD_MVERT, mesh->mvert); + CustomData_set_layer(&mesh->edata, CD_MEDGE, mesh->medge); + 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; + } + else { + medge[new_edge].v2 = new_vert; + } + + ml->v = new_vert; + ml_prev->e = new_edge_prev; + ml->e = new_edge; + num_new_verts++; + } + } + } +} + /* settings: 1 - preview, 2 - render */ Mesh *BKE_mesh_new_from_object( Main *bmain, Scene *sce, Object *ob, @@ -2213,8 +2398,8 @@ Mesh *BKE_mesh_new_from_object( * only contains for_render flag. As soon as CoW is * implemented, this is to be rethinked. */ - EvaluationContext eval_ctx = {0}; - eval_ctx.mode = DAG_EVAL_RENDER; + EvaluationContext eval_ctx; + DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_RENDER); BKE_displist_make_mball_forRender(&eval_ctx, sce, ob, &disp); BKE_mesh_from_metaball(&disp, tmpmesh); BKE_displist_free(&disp); @@ -2339,3 +2524,75 @@ Mesh *BKE_mesh_new_from_object( return tmpmesh; } +/* settings: 1 - preview, 2 - render */ +Mesh *BKE_mesh_new_from_dupli_data( + Main *bmain, DupliObjectData *data, + bool calc_tessface, bool calc_undeformed) +{ + Object *ob = data->ob; + DerivedMesh *dm = data->dm; + CustomDataMask mask; + + Mesh *tmpmesh; + + if (!ob || !dm) + return NULL; + + mask = CD_MASK_MESH; /* this seems more suitable, exporter, + * for example, needs CD_MASK_MDEFORMVERT */ + if (calc_undeformed) + mask |= CD_MASK_ORCO; + + tmpmesh = BKE_mesh_add(bmain, "Mesh"); + DM_to_mesh(dm, tmpmesh, ob, mask, true); + + /* BKE_mesh_add/copy gives us a user count we don't need */ + tmpmesh->id.us--; + + /* Copy materials to new mesh */ + switch (ob->type) { + case OB_MESH: { + Mesh *origmesh = ob->data; + int i; + + tmpmesh->flag = origmesh->flag; + tmpmesh->mat = MEM_dupallocN(origmesh->mat); + tmpmesh->totcol = origmesh->totcol; + tmpmesh->smoothresh = origmesh->smoothresh; + if (origmesh->mat) { + for (i = origmesh->totcol; i-- > 0; ) { + /* are we an object material or data based? */ + tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : origmesh->mat[i]; + + if (tmpmesh->mat[i]) { + tmpmesh->mat[i]->id.us++; + } + } + } + break; + } + } /* end copy materials */ + + if (calc_tessface) { + /* cycles and exporters rely on this still */ + BKE_mesh_tessface_ensure(tmpmesh); + } + + /* make sure materials get updated in objects */ + test_object_materials(bmain, &tmpmesh->id); + + return tmpmesh; +} + +/* **** Depsgraph evaluation **** */ + +void BKE_mesh_eval_geometry(EvaluationContext *UNUSED(eval_ctx), + Mesh *mesh) +{ + if (G.debug & G_DEBUG_DEPSGRAPH) { + printf("%s on %s\n", __func__, mesh->id.name); + } + if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) { + BKE_mesh_texspace_calc(mesh); + } +} |