Mesh: skip conversion from edit-mesh to mesh in edit-mode

This resolves a performance regression in 2.8x where every edit-mode
update performed an edit-mesh to mesh conversion.

Now the conversion will be lazily initialized if/when it's required.

New BKE_mesh_wrapper_* functions abstract over mesh data access.
Currently only edit-mesh and regular meshes are supported.
In the future sub-surface meshes may be supported too.
This commit is contained in:
2020-05-25 20:16:42 +10:00
parent df8cbdc696
commit deaff945d0
36 changed files with 860 additions and 184 deletions

View File

@@ -90,6 +90,8 @@
static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
static void mesh_init_origspace(Mesh *mesh);
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
const CustomData_MeshMasks *final_datamask);
/* -------------------------------------------------------------------- */
@@ -861,6 +863,16 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
mesh_eval->edit_mesh = mesh_input->edit_mesh;
}
void BKE_mesh_wrapper_deferred_finalize(Mesh *me_eval,
const CustomData_MeshMasks *cd_mask_finalize)
{
if (me_eval->runtime.wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) {
editbmesh_calc_modifier_final_normals(me_eval, cd_mask_finalize);
me_eval->runtime.wrapper_type_finalize &= ~(1 << ME_WRAPPER_TYPE_BMESH);
}
BLI_assert(me_eval->runtime.wrapper_type_finalize == 0);
}
static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -1391,11 +1403,16 @@ bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, bool has_prev
return true;
}
static void editbmesh_calc_modifier_final_normals(const Mesh *mesh_input,
const CustomData_MeshMasks *final_datamask,
Mesh *mesh_final)
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
const CustomData_MeshMasks *final_datamask)
{
const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
if (mesh_final->runtime.wrapper_type != ME_WRAPPER_TYPE_MDATA) {
/* Generated at draw time. */
mesh_final->runtime.wrapper_type_finalize = (1 << mesh_final->runtime.wrapper_type);
return;
}
const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
/* Some modifiers may need this info from their target (other) object,
* simpler to generate it here as well. */
@@ -1501,7 +1518,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Evaluate modifiers up to certain index to get the mesh cage. */
int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1);
if (r_cage && cageIndex == -1) {
mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input, &final_datamask, NULL, mesh_input);
}
@@ -1574,12 +1591,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
else {
mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
if (deformed_verts) {
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
}
mesh_final = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input, NULL, deformed_verts, mesh_input);
deformed_verts = NULL;
}
/* create an orco derivedmesh in parallel */
@@ -1657,7 +1671,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
BKE_mesh_runtime_ensure_edit_data(me_orig);
me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts);
}
mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input,
&final_datamask,
deformed_verts ? MEM_dupallocN(deformed_verts) : NULL,
@@ -1689,7 +1703,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
else {
/* this is just a copy of the editmesh, no need to calc normals */
mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(
mesh_final = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input, &final_datamask, deformed_verts, mesh_input);
deformed_verts = NULL;
}
@@ -1700,6 +1714,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Add orco coordinates to final and deformed mesh if requested. */
if (final_datamask.vmask & CD_MASK_ORCO) {
/* FIXME(Campbell): avoid the need to convert to mesh data just to add an orco layer. */
BKE_mesh_wrapper_ensure_mdata(mesh_final);
add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO);
}
@@ -1707,10 +1724,15 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
BKE_id_free(NULL, mesh_orco);
}
/* Ensure normals calculation below is correct. */
BLI_assert((mesh_input->flag & ME_AUTOSMOOTH) == (mesh_final->flag & ME_AUTOSMOOTH));
BLI_assert(mesh_input->smoothresh == mesh_final->smoothresh);
BLI_assert(mesh_input->smoothresh == mesh_cage->smoothresh);
/* Compute normals. */
editbmesh_calc_modifier_final_normals(mesh_input, &final_datamask, mesh_final);
editbmesh_calc_modifier_final_normals(mesh_final, &final_datamask);
if (mesh_cage && (mesh_cage != mesh_final)) {
editbmesh_calc_modifier_final_normals(mesh_input, &final_datamask, mesh_cage);
editbmesh_calc_modifier_final_normals(mesh_cage, &final_datamask);
}
/* Return final mesh. */

View File

@@ -293,7 +293,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
cd_mask_extra = datamasks->mask;
BLI_linklist_free((LinkNode *)datamasks, NULL);
me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &cd_mask_extra, NULL, me_input);
me = BKE_mesh_wrapper_from_editmesh_with_coords(em, &cd_mask_extra, NULL, me_input);
deformedVerts = editbmesh_vert_coords_alloc(em, &numVerts);
defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats");

View File

@@ -32,6 +32,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_iterators.h"
@@ -266,7 +267,7 @@ BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em)
float min[3], max[3];
INIT_MINMAX(min, max);
if (em->mesh_eval_cage) {
BKE_mesh_minmax(em->mesh_eval_cage, min, max);
BKE_mesh_wrapper_minmax(em->mesh_eval_cage, min, max);
}
em->bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage");

View File

@@ -22,11 +22,17 @@
#include "MEM_guardedalloc.h"
#include "BLI_math_vector.h"
#include "DNA_mesh_types.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h" /* own include */
/* -------------------------------------------------------------------- */
/** \name Ensure Data (derived from coords)
* \{ */
void BKE_editmesh_cache_ensure_poly_normals(BMEditMesh *em, EditMeshData *emd)
{
if (!(emd->vertexCos && (emd->polyNos == NULL))) {
@@ -112,3 +118,41 @@ void BKE_editmesh_cache_ensure_poly_centers(BMEditMesh *em, EditMeshData *emd)
emd->polyCos = (const float(*)[3])polyCos;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Calculate Min/Max
* \{ */
bool BKE_editmesh_cache_calc_minmax(struct BMEditMesh *em,
struct EditMeshData *emd,
float min[3],
float max[3])
{
BMesh *bm = em->bm;
BMVert *eve;
BMIter iter;
int i;
if (bm->totvert) {
if (emd->vertexCos) {
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
minmax_v3v3_v3(min, max, emd->vertexCos[i]);
}
}
else {
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
minmax_v3v3_v3(min, max, eve->co);
}
}
return true;
}
else {
zero_v3(min);
zero_v3(max);
return false;
}
}
/** \} */

View File

@@ -866,26 +866,6 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm,
return mesh;
}
/**
* TODO(campbell): support mesh with only an edit-mesh which is lazy initialized.
*/
Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(BMEditMesh *em,
const CustomData_MeshMasks *cd_mask_extra,
float (*vertexCos)[3],
const Mesh *me_settings)
{
Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, cd_mask_extra, me_settings);
/* Use editmesh directly where possible. */
me->runtime.is_original = true;
if (vertexCos) {
/* We will own this array in the future. */
BKE_mesh_vert_coords_apply(me, vertexCos);
MEM_freeN(vertexCos);
me->runtime.is_original = false;
}
return me;
}
BoundBox *BKE_mesh_boundbox_get(Object *ob)
{
/* This is Object-level data access,
@@ -895,7 +875,7 @@ BoundBox *BKE_mesh_boundbox_get(Object *ob)
float min[3], max[3];
INIT_MINMAX(min, max);
if (!BKE_mesh_minmax(me, min, max)) {
if (!BKE_mesh_wrapper_minmax(me, min, max)) {
min[0] = min[1] = min[2] = -1.0f;
max[0] = max[1] = max[2] = 1.0f;
}
@@ -916,7 +896,7 @@ void BKE_mesh_texspace_calc(Mesh *me)
float min[3], max[3];
INIT_MINMAX(min, max);
if (!BKE_mesh_minmax(me, min, max)) {
if (!BKE_mesh_wrapper_minmax(me, min, max)) {
min[0] = min[1] = min[2] = -1.0f;
max[0] = max[1] = max[2] = 1.0f;
}

View File

@@ -1076,6 +1076,10 @@ static Mesh *mesh_new_from_mball_object(Object *object)
static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh)
{
/* While we could copy this into the new mesh,
* add the data to 'mesh' so future calls to this function don't need to re-convert the data. */
BKE_mesh_wrapper_ensure_mdata(mesh);
Mesh *mesh_result = NULL;
BKE_id_copy_ex(NULL,
&mesh->id,

View File

@@ -46,6 +46,7 @@
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
#include "BKE_editmesh_cache.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
@@ -396,6 +397,21 @@ void BKE_mesh_ensure_normals(Mesh *mesh)
*/
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
{
switch ((eMeshWrapperType)mesh->runtime.wrapper_type) {
case ME_WRAPPER_TYPE_MDATA:
/* Run code below. */
break;
case ME_WRAPPER_TYPE_BMESH: {
struct BMEditMesh *em = mesh->edit_mesh;
EditMeshData *emd = mesh->runtime.edit_data;
if (emd->vertexCos) {
BKE_editmesh_cache_ensure_vert_normals(em, emd);
BKE_editmesh_cache_ensure_poly_normals(em, emd);
}
return;
}
}
float(*poly_nors)[3] = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
const bool do_vert_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) != 0;
const bool do_poly_normals = (mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL || poly_nors == NULL);

View File

@@ -24,6 +24,8 @@
#include "DNA_meshdata_types.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h"
#include "BKE_mesh.h"
#include "BKE_mesh_iterators.h"
@@ -42,23 +44,53 @@ void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
void *userData,
MeshForeachFlag flag)
{
const MVert *mv = mesh->mvert;
const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
if (index) {
for (int i = 0; i < mesh->totvert; i++, mv++) {
const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
const int orig = *index++;
if (orig == ORIGINDEX_NONE) {
continue;
if (mesh->edit_mesh != NULL) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
BMIter iter;
BMVert *eve;
int i;
if (mesh->runtime.edit_data->vertexCos != NULL) {
const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
const float(*vertexNos)[3];
if (flag & MESH_FOREACH_USE_NORMAL) {
BKE_editmesh_cache_ensure_vert_normals(em, mesh->runtime.edit_data);
vertexNos = mesh->runtime.edit_data->vertexNos;
}
else {
vertexNos = NULL;
}
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vertexNos[i] : NULL;
func(userData, i, vertexCos[i], no, NULL);
}
}
else {
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? eve->no : NULL;
func(userData, i, eve->co, no, NULL);
}
func(userData, orig, mv->co, NULL, no);
}
}
else {
for (int i = 0; i < mesh->totvert; i++, mv++) {
const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
func(userData, i, mv->co, NULL, no);
const MVert *mv = mesh->mvert;
const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
if (index) {
for (int i = 0; i < mesh->totvert; i++, mv++) {
const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
const int orig = *index++;
if (orig == ORIGINDEX_NONE) {
continue;
}
func(userData, orig, mv->co, NULL, no);
}
}
else {
for (int i = 0; i < mesh->totvert; i++, mv++) {
const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
func(userData, i, mv->co, NULL, no);
}
}
}
}
@@ -69,22 +101,47 @@ void BKE_mesh_foreach_mapped_edge(
void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
void *userData)
{
const MVert *mv = mesh->mvert;
const MEdge *med = mesh->medge;
const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX);
if (mesh->edit_mesh != NULL) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
BMIter iter;
BMEdge *eed;
int i;
if (mesh->runtime.edit_data->vertexCos != NULL) {
const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
BM_mesh_elem_index_ensure(bm, BM_VERT);
if (index) {
for (int i = 0; i < mesh->totedge; i++, med++) {
const int orig = *index++;
if (orig == ORIGINDEX_NONE) {
continue;
BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
func(userData,
i,
vertexCos[BM_elem_index_get(eed->v1)],
vertexCos[BM_elem_index_get(eed->v2)]);
}
}
else {
BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
func(userData, i, eed->v1->co, eed->v2->co);
}
func(userData, orig, mv[med->v1].co, mv[med->v2].co);
}
}
else {
for (int i = 0; i < mesh->totedge; i++, med++) {
func(userData, i, mv[med->v1].co, mv[med->v2].co);
const MVert *mv = mesh->mvert;
const MEdge *med = mesh->medge;
const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX);
if (index) {
for (int i = 0; i < mesh->totedge; i++, med++) {
const int orig = *index++;
if (orig == ORIGINDEX_NONE) {
continue;
}
func(userData, orig, mv[med->v1].co, mv[med->v2].co);
}
}
else {
for (int i = 0; i < mesh->totedge; i++, med++) {
func(userData, i, mv[med->v1].co, mv[med->v2].co);
}
}
}
}
@@ -99,40 +156,72 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
void *userData,
MeshForeachFlag flag)
{
/* We can't use dm->getLoopDataLayout(dm) here,
* we want to always access dm->loopData, EditDerivedBMesh would
* return loop data from bmesh itself. */
const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
CustomData_get_layer(&mesh->ldata, CD_NORMAL) :
NULL;
if (mesh->edit_mesh != NULL) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
BMIter iter;
BMFace *efa;
const MVert *mv = mesh->mvert;
const MLoop *ml = mesh->mloop;
const MPoly *mp = mesh->mpoly;
const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
int p_idx, i;
const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
if (v_index || f_index) {
for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
for (i = 0; i < mp->totloop; i++, ml++) {
const int v_idx = v_index ? v_index[ml->v] : ml->v;
const int f_idx = f_index ? f_index[p_idx] : p_idx;
/* XXX: investigate using EditMesh data. */
const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
CustomData_get_layer(&mesh->ldata, CD_NORMAL) :
NULL;
int f_idx;
BM_mesh_elem_index_ensure(bm, BM_VERT);
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, f_idx) {
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
do {
const BMVert *eve = l_iter->v;
const int v_idx = BM_elem_index_get(eve);
const float *no = lnors ? *lnors++ : NULL;
if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
continue;
}
func(userData, v_idx, f_idx, mv[ml->v].co, no);
}
func(userData, v_idx, f_idx, vertexCos ? vertexCos[v_idx] : eve->co, no);
} while ((l_iter = l_iter->next) != l_first);
}
}
else {
for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
for (i = 0; i < mp->totloop; i++, ml++) {
const int v_idx = ml->v;
const int f_idx = p_idx;
const float *no = lnors ? *lnors++ : NULL;
func(userData, v_idx, f_idx, mv[ml->v].co, no);
const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
CustomData_get_layer(&mesh->ldata, CD_NORMAL) :
NULL;
const MVert *mv = mesh->mvert;
const MLoop *ml = mesh->mloop;
const MPoly *mp = mesh->mpoly;
const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
int p_idx, i;
if (v_index || f_index) {
for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
for (i = 0; i < mp->totloop; i++, ml++) {
const int v_idx = v_index ? v_index[ml->v] : ml->v;
const int f_idx = f_index ? f_index[p_idx] : p_idx;
const float *no = lnors ? *lnors++ : NULL;
if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
continue;
}
func(userData, v_idx, f_idx, mv[ml->v].co, no);
}
}
}
else {
for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
for (i = 0; i < mp->totloop; i++, ml++) {
const int v_idx = ml->v;
const int f_idx = p_idx;
const float *no = lnors ? *lnors++ : NULL;
func(userData, v_idx, f_idx, mv[ml->v].co, no);
}
}
}
}
@@ -145,37 +234,72 @@ void BKE_mesh_foreach_mapped_face_center(
void *userData,
MeshForeachFlag flag)
{
const MVert *mvert = mesh->mvert;
const MPoly *mp = mesh->mpoly;
const MLoop *ml;
float _no_buf[3];
float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL;
const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
if (mesh->edit_mesh != NULL) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
const float(*polyCos)[3];
const float(*polyNos)[3];
BMFace *efa;
BMIter iter;
int i;
if (index) {
for (int i = 0; i < mesh->totpoly; i++, mp++) {
const int orig = *index++;
if (orig == ORIGINDEX_NONE) {
continue;
BKE_editmesh_cache_ensure_poly_centers(em, mesh->runtime.edit_data);
polyCos = mesh->runtime.edit_data->polyCos; /* always set */
if (flag & MESH_FOREACH_USE_NORMAL) {
BKE_editmesh_cache_ensure_poly_normals(em, mesh->runtime.edit_data);
polyNos = mesh->runtime.edit_data->polyNos; /* maybe NULL */
}
else {
polyNos = NULL;
}
if (polyNos) {
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
const float *no = polyNos[i];
func(userData, i, polyCos[i], no);
}
float cent[3];
ml = &mesh->mloop[mp->loopstart];
BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
if (flag & MESH_FOREACH_USE_NORMAL) {
BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
}
else {
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? efa->no : NULL;
func(userData, i, polyCos[i], no);
}
func(userData, orig, cent, no);
}
}
else {
for (int i = 0; i < mesh->totpoly; i++, mp++) {
float cent[3];
ml = &mesh->mloop[mp->loopstart];
BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
if (flag & MESH_FOREACH_USE_NORMAL) {
BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
const MVert *mvert = mesh->mvert;
const MPoly *mp = mesh->mpoly;
const MLoop *ml;
float _no_buf[3];
float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL;
const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
if (index) {
for (int i = 0; i < mesh->totpoly; i++, mp++) {
const int orig = *index++;
if (orig == ORIGINDEX_NONE) {
continue;
}
float cent[3];
ml = &mesh->mloop[mp->loopstart];
BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
if (flag & MESH_FOREACH_USE_NORMAL) {
BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
}
func(userData, orig, cent, no);
}
}
else {
for (int i = 0; i < mesh->totpoly; i++, mp++) {
float cent[3];
ml = &mesh->mloop[mp->loopstart];
BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
if (flag & MESH_FOREACH_USE_NORMAL) {
BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
}
func(userData, i, cent, no);
}
func(userData, i, cent, no);
}
}
}

View File

@@ -0,0 +1,165 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bke
*
* The primary purpose of this API is to avoid unnecessary mesh conversion for the final
* output of a modified mesh.
*
* This API handles the case when the modifier stack outputs a mesh which does not have
* #Mesh data (#MPoly, #MLoop, #MEdge, #MVert).
* Currently this is used so the resulting mesh can have #BMEditMesh data,
* postponing the converting until it's needed or avoiding conversion entirely
* which can be an expensive operation.
* Once converted, the meshes type changes to #ME_WRAPPER_TYPE_MDATA,
* although the edit mesh is not cleared.
*
* This API exposes functions that abstract over the different kinds of internal data,
* as well as supporting converting the mesh into regular mesh.
*/
#include "MEM_guardedalloc.h"
#include "DNA_defaults.h"
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BLI_bitmap.h"
#include "BLI_edgehash.h"
#include "BLI_ghash.h"
#include "BLI_hash.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
#include "BKE_animsys.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_object.h"
#include "PIL_time.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
const CustomData_MeshMasks *cd_mask_extra,
float (*vertexCos)[3],
const Mesh *me_settings)
{
Mesh *me = BKE_id_new_nomain(ID_ME, NULL);
BKE_mesh_copy_settings(me, me_settings);
BKE_mesh_runtime_ensure_edit_data(me);
me->runtime.wrapper_type = ME_WRAPPER_TYPE_BMESH;
if (cd_mask_extra) {
me->runtime.cd_mask_extra = *cd_mask_extra;
}
/* Use edit-mesh directly where possible. */
me->runtime.is_original = true;
me->edit_mesh = MEM_dupallocN(em);
/* Make sure, we crash if these are ever used. */
#ifdef DEBUG
me->totvert = INT_MAX;
me->totedge = INT_MAX;
me->totpoly = INT_MAX;
me->totloop = INT_MAX;
#else
me->totvert = 0;
me->totedge = 0;
me->totpoly = 0;
me->totloop = 0;
#endif
EditMeshData *edit_data = me->runtime.edit_data;
edit_data->vertexCos = vertexCos;
return me;
}
Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em,
const CustomData_MeshMasks *cd_mask_extra,
const Mesh *me_settings)
{
return BKE_mesh_wrapper_from_editmesh_with_coords(em, cd_mask_extra, NULL, me_settings);
}
void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
{
if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
return;
}
const eMeshWrapperType geom_type_orig = me->runtime.wrapper_type;
me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
switch (geom_type_orig) {
case ME_WRAPPER_TYPE_MDATA: {
break; /* Quiet warning. */
}
case ME_WRAPPER_TYPE_BMESH: {
me->totvert = 0;
me->totedge = 0;
me->totpoly = 0;
me->totloop = 0;
BLI_assert(me->edit_mesh != NULL);
BLI_assert(me->runtime.edit_data != NULL);
BMEditMesh *em = me->edit_mesh;
BM_mesh_bm_to_me_for_eval(em->bm, me, &me->runtime.cd_mask_extra);
EditMeshData *edit_data = me->runtime.edit_data;
if (edit_data->vertexCos) {
BKE_mesh_vert_coords_apply(me, edit_data->vertexCos);
me->runtime.is_original = false;
}
break;
}
}
if (me->runtime.wrapper_type_finalize) {
BKE_mesh_wrapper_deferred_finalize(me, &me->runtime.cd_mask_extra);
}
}
bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3])
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime.edit_data, min, max);
case ME_WRAPPER_TYPE_MDATA:
return BKE_mesh_minmax(me, min, max);
}
BLI_assert(0);
}

View File

@@ -50,6 +50,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_appdir.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
@@ -934,6 +935,30 @@ void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
BLI_join_dirfile(path, path_maxlen, G.relbase_valid ? "//" : BKE_tempdir_session(), name);
}
/**
* Call when #ModifierTypeInfo.dependsOnNormals callback requests normals.
*/
static void modwrap_dependsOnNormals(Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: {
EditMeshData *edit_data = me->runtime.edit_data;
if (edit_data->vertexCos) {
/* Note that 'ensure' is acceptable here since these values aren't modified in-place.
* If that changes we'll need to recalculate. */
BKE_editmesh_cache_ensure_vert_normals(me->edit_mesh, edit_data);
}
else {
BM_mesh_normals_update(me->edit_mesh->bm);
}
break;
}
case ME_WRAPPER_TYPE_MDATA:
BKE_mesh_calc_normals(me);
break;
}
}
/* wrapper around ModifierTypeInfo.modifyMesh that ensures valid normals */
struct Mesh *BKE_modifier_modify_mesh(ModifierData *md,
@@ -943,8 +968,14 @@ struct Mesh *BKE_modifier_modify_mesh(ModifierData *md,
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
if ((mti->flags & eModifierTypeFlag_AcceptsBMesh) == 0) {
BKE_mesh_wrapper_ensure_mdata(me);
}
}
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
BKE_mesh_calc_normals(me);
modwrap_dependsOnNormals(me);
}
return mti->modifyMesh(md, ctx, me);
}
@@ -959,7 +990,7 @@ void BKE_modifier_deform_verts(ModifierData *md,
BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
BKE_mesh_calc_normals(me);
modwrap_dependsOnNormals(me);
}
mti->deformVerts(md, ctx, me, vertexCos, numVerts);
}

View File

@@ -81,6 +81,7 @@
#include "BKE_displist.h"
#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_fcurve_driver.h"
@@ -3089,7 +3090,7 @@ void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval)
INIT_MINMAX(min, max);
if (!BKE_mesh_minmax(me_eval, min, max)) {
if (!BKE_mesh_wrapper_minmax(me_eval, min, max)) {
zero_v3(min);
zero_v3(max);
}