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

@@ -33,6 +33,11 @@ void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, struct EditMe
void BKE_editmesh_cache_ensure_poly_centers(struct BMEditMesh *em, struct EditMeshData *emd);
bool BKE_editmesh_cache_calc_minmax(struct BMEditMesh *em,
struct EditMeshData *emd,
float min[3],
float max[3]);
#ifdef __cplusplus
}
#endif

View File

@@ -85,12 +85,6 @@ struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm,
const struct CustomData_MeshMasks *cd_mask_extra,
const struct Mesh *me_settings);
struct Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(
struct BMEditMesh *em,
const struct CustomData_MeshMasks *cd_mask_extra,
float (*vertexCos)[3],
const struct Mesh *me_settings);
int poly_find_loop_from_vert(const struct MPoly *poly, const struct MLoop *loopstart, uint vert);
int poly_get_adj_loops_from_vert(const struct MPoly *poly,
const struct MLoop *mloop,
@@ -673,6 +667,23 @@ void BKE_mesh_calc_edges_loose(struct Mesh *mesh);
void BKE_mesh_calc_edges(struct Mesh *mesh, bool update, const bool select);
void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
/* *** mesh_geomtype.c *** */
struct Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(
struct BMEditMesh *em,
const struct CustomData_MeshMasks *cd_mask_extra,
float (*vertexCos)[3],
const struct Mesh *me_settings);
struct Mesh *BKE_mesh_wrapper_from_editmesh(struct BMEditMesh *em,
const struct CustomData_MeshMasks *cd_mask_extra,
const struct Mesh *me_settings);
void BKE_mesh_wrapper_ensure_mdata(struct Mesh *me);
bool BKE_mesh_wrapper_minmax(const struct Mesh *me, float min[3], float max[3]);
void BKE_mesh_wrapper_normals_update(struct Mesh *me);
/* In DerivedMesh.c */
void BKE_mesh_wrapper_deferred_finalize(struct Mesh *me_eval,
const CustomData_MeshMasks *final_datamask);
/* **** Depsgraph evaluation **** */
void BKE_mesh_eval_geometry(struct Depsgraph *depsgraph, struct Mesh *mesh);

View File

@@ -101,6 +101,9 @@ typedef enum {
/* For modifiers that use CD_PREVIEW_MCOL for preview. */
eModifierTypeFlag_UsesPreview = (1 << 9),
eModifierTypeFlag_AcceptsVertexCosOnly = (1 << 10),
/** Accepts #BMesh input (without conversion). */
eModifierTypeFlag_AcceptsBMesh = (1 << 11),
} ModifierTypeFlag;
/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */

View File

@@ -168,6 +168,7 @@ set(SRC
intern/mesh_runtime.c
intern/mesh_tangent.c
intern/mesh_validate.c
intern/mesh_wrapper.c
intern/modifier.c
intern/movieclip.c
intern/multires.c

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);
}

View File

@@ -1567,6 +1567,41 @@ float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq,
}
}
/**
* A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates.
*/
float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
const float normal_fallback[3],
float const (*vertexCos)[3],
const float epsilon_sq,
float r_normal[3])
{
const int i_prev = BM_elem_index_get(l->prev->v);
const int i_next = BM_elem_index_get(l->next->v);
const int i = BM_elem_index_get(l->v);
float v1[3], v2[3], v_tmp[3];
sub_v3_v3v3(v1, vertexCos[i_prev], vertexCos[i]);
sub_v3_v3v3(v2, vertexCos[i_next], vertexCos[i]);
const float fac = ((v2[0] == 0.0f) ?
((v2[1] == 0.0f) ? ((v2[2] == 0.0f) ? 0.0f : v1[2] / v2[2]) :
v1[1] / v2[1]) :
v1[0] / v2[0]);
mul_v3_v3fl(v_tmp, v2, fac);
sub_v3_v3(v_tmp, v1);
if (fac != 0.0f && !is_zero_v3(v1) && len_squared_v3(v_tmp) > epsilon_sq) {
/* Not co-linear, we can compute cross-product and normalize it into normal. */
cross_v3_v3v3(r_normal, v1, v2);
return normalize_v3(r_normal);
}
else {
copy_v3_v3(r_normal, normal_fallback);
return 0.0f;
}
}
/**
* #BM_loop_calc_face_normal_safe_ex with pre-defined sane epsilon.
*
@@ -1577,6 +1612,15 @@ float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3])
return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal);
}
float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
const float normal_fallback[3],
float const (*vertexCos)[3],
float r_normal[3])
{
return BM_loop_calc_face_normal_safe_vcos_ex(l, normal_fallback, vertexCos, 1e-5f, r_normal);
}
/**
* \brief BM_loop_calc_face_normal
*

View File

@@ -142,6 +142,16 @@ float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL(
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon, float r_normal[3])
ATTR_NONNULL();
float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
const float normal_fallback[3],
float const (*vertexCos)[3],
const float epsilon_sq,
float r_normal[3]) ATTR_NONNULL();
float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
const float normal_fallback[3],
float const (*vertexCos)[3],
float r_normal[3]) ATTR_NONNULL();
void BM_loop_calc_face_direction(const BMLoop *l, float r_normal[3]);
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]);

View File

@@ -105,6 +105,14 @@ typedef struct MeshRenderData {
BMEditMesh *edit_bmesh;
BMesh *bm;
EditMeshData *edit_data;
/* For deformed edit-mesh data. */
/* Use for #ME_WRAPPER_TYPE_BMESH. */
const float (*bm_vert_coords)[3];
const float (*bm_vert_normals)[3];
const float (*bm_poly_normals)[3];
const float (*bm_poly_centers)[3];
int *v_origindex, *e_origindex, *p_origindex;
int crease_ofs;
int bweight_ofs;
@@ -151,9 +159,24 @@ static MeshRenderData *mesh_render_data_create(Mesh *me,
BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final);
mr->bm = me->edit_mesh->bm;
mr->edit_bmesh = me->edit_mesh;
mr->edit_data = me->runtime.edit_data;
mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage;
bool use_mapped = !do_uvedit && mr->me && !mr->me->runtime.is_original;
mr->edit_data = mr->me->runtime.edit_data;
if (mr->edit_data) {
EditMeshData *emd = mr->edit_data;
if (emd->vertexCos) {
BKE_editmesh_cache_ensure_vert_normals(mr->edit_bmesh, emd);
BKE_editmesh_cache_ensure_poly_normals(mr->edit_bmesh, emd);
}
mr->bm_vert_coords = mr->edit_data->vertexCos;
mr->bm_vert_normals = mr->edit_data->vertexNos;
mr->bm_poly_normals = mr->edit_data->polyNos;
mr->bm_poly_centers = mr->edit_data->polyCos;
}
bool has_mdata = (mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA);
bool use_mapped = has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original;
int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE;
@@ -184,7 +207,7 @@ static MeshRenderData *mesh_render_data_create(Mesh *me,
/* Seems like the mesh_eval_final do not have the right origin indices.
* Force not mapped in this case. */
if (do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) {
if (has_mdata && do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) {
// mr->edit_bmesh = NULL;
mr->extract_type = MR_EXTRACT_MESH;
}
@@ -311,12 +334,23 @@ static MeshRenderData *mesh_render_data_create(Mesh *me,
/* Use bmface->no instead. */
}
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
const float(*vert_coords)[3] = NULL;
const float(*vert_normals)[3] = NULL;
const float(*poly_normals)[3] = NULL;
if (mr->edit_data && mr->edit_data->vertexCos) {
vert_coords = mr->bm_vert_coords;
vert_normals = mr->bm_vert_normals;
poly_normals = mr->bm_poly_normals;
}
mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL);
BM_loops_calc_normal_vcos(mr->bm,
NULL,
NULL,
NULL,
vert_coords,
vert_normals,
poly_normals,
is_auto_smooth,
split_angle,
mr->loop_normals,
@@ -396,6 +430,42 @@ BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx)
NULL;
}
BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve)
{
const float(*vert_coords)[3] = mr->bm_vert_coords;
if (vert_coords != NULL) {
return vert_coords[BM_elem_index_get(eve)];
}
else {
UNUSED_VARS(mr);
return eve->co;
}
}
BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve)
{
const float(*vert_normals)[3] = mr->bm_vert_normals;
if (vert_normals != NULL) {
return vert_normals[BM_elem_index_get(eve)];
}
else {
UNUSED_VARS(mr);
return eve->co;
}
}
BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa)
{
const float(*poly_normals)[3] = mr->bm_poly_normals;
if (poly_normals != NULL) {
return poly_normals[BM_elem_index_get(efa)];
}
else {
UNUSED_VARS(mr);
return efa->no;
}
}
/** \} */
/* ---------------------------------------------------------------------- */
@@ -1480,7 +1550,7 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf)
BMVert *eve;
int v;
BM_ITER_MESH_INDEX (eve, &iter, mr->bm, BM_VERTS_OF_MESH, v) {
data->packed_nor[v] = GPU_normal_convert_i10_v3(eve->no);
data->packed_nor[v] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, eve));
}
}
else {
@@ -1492,14 +1562,11 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf)
return data;
}
static void extract_pos_nor_loop_bmesh(const MeshRenderData *UNUSED(mr),
int l,
BMLoop *loop,
void *_data)
static void extract_pos_nor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data)
{
MeshExtract_PosNor_Data *data = _data;
PosNorLoop *vert = data->vbo_data + l;
copy_v3_v3(vert->pos, loop->v->co);
copy_v3_v3(vert->pos, bm_vert_co_get(mr, loop->v));
vert->nor = data->packed_nor[BM_elem_index_get(loop->v)];
BMFace *efa = loop->f;
vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
@@ -1536,8 +1603,8 @@ static void extract_pos_nor_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge
int l = mr->loop_len + e * 2;
MeshExtract_PosNor_Data *data = _data;
PosNorLoop *vert = data->vbo_data + l;
copy_v3_v3(vert[0].pos, eed->v1->co);
copy_v3_v3(vert[1].pos, eed->v2->co);
copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1));
copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2));
vert[0].nor = data->packed_nor[BM_elem_index_get(eed->v1)];
vert[1].nor = data->packed_nor[BM_elem_index_get(eed->v2)];
}
@@ -1561,7 +1628,7 @@ static void extract_pos_nor_lvert_bmesh(const MeshRenderData *mr, int v, BMVert
int l = mr->loop_len + mr->edge_loose_len * 2 + v;
MeshExtract_PosNor_Data *data = _data;
PosNorLoop *vert = data->vbo_data + l;
copy_v3_v3(vert->pos, eve->co);
copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve));
vert->nor = data->packed_nor[BM_elem_index_get(eve)];
}
@@ -1627,10 +1694,10 @@ static void extract_lnor_hq_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *
normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, mr->loop_normals[l]);
}
else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) {
normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, loop->v->no);
normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_vert_no_get(mr, loop->v));
}
else {
normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, loop->f->no);
normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_face_no_get(mr, loop->f));
}
}
@@ -1704,10 +1771,10 @@ static void extract_lnor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loo
((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->loop_normals[l]);
}
else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) {
((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(loop->v->no);
((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, loop->v));
}
else {
((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(loop->f->no);
((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, loop->f));
}
BMFace *efa = loop->f;
((GPUPackedNormal *)data)[l].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
@@ -1915,7 +1982,10 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool
if (mr->extract_type == MR_EXTRACT_BMESH) {
BMesh *bm = mr->bm;
for (int v = 0; v < mr->vert_len; v++) {
copy_v3_v3(orco[v], BM_vert_at_index(bm, v)->co);
const BMVert *eve = BM_vert_at_index(bm, v);
/* Exceptional case where #bm_vert_co_get can be avoided, as we want the original coords.
* not the distorted ones. */
copy_v3_v3(orco[v], eve->co);
}
}
else {
@@ -2301,14 +2371,14 @@ static void *extract_edge_fac_init(const MeshRenderData *mr, void *buf)
return data;
}
static void extract_edge_fac_loop_bmesh(const MeshRenderData *UNUSED(mr),
int l,
BMLoop *loop,
void *_data)
static void extract_edge_fac_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data)
{
MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
if (BM_edge_is_manifold(loop->e)) {
float ratio = loop_edge_factor_get(loop->f->no, loop->v->co, loop->v->no, loop->next->v->co);
float ratio = loop_edge_factor_get(bm_face_no_get(mr, loop->f),
bm_vert_co_get(mr, loop->v),
bm_vert_no_get(mr, loop->v),
bm_vert_co_get(mr, loop->next->v));
data->vbo_data[l] = ratio * 253 + 1;
}
else {
@@ -3133,7 +3203,7 @@ static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf)
return data;
}
static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr),
static void extract_stretch_angle_loop_bmesh(const MeshRenderData *mr,
int l,
BMLoop *loop,
void *_data)
@@ -3150,8 +3220,12 @@ static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr),
BMLoop *l_next_tmp = loop;
luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs);
luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs);
compute_normalize_edge_vectors(
auv, av, luv->uv, luv_next->uv, l_tmp->v->co, l_next_tmp->v->co);
compute_normalize_edge_vectors(auv,
av,
luv->uv,
luv_next->uv,
bm_vert_co_get(mr, l_tmp->v),
bm_vert_co_get(mr, l_next_tmp->v));
/* Save last edge. */
copy_v2_v2(last_auv, auv[1]);
copy_v3_v3(last_av, av[1]);
@@ -3167,7 +3241,12 @@ static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr),
else {
luv = BM_ELEM_CD_GET_VOID_P(loop, data->cd_ofs);
luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs);
compute_normalize_edge_vectors(auv, av, luv->uv, luv_next->uv, loop->v->co, l_next->v->co);
compute_normalize_edge_vectors(auv,
av,
luv->uv,
luv_next->uv,
bm_vert_co_get(mr, loop->v),
bm_vert_co_get(mr, l_next->v));
}
edituv_get_stretch_angle(auv, av, data->vbo_data + l);
}
@@ -3307,7 +3386,7 @@ static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang)
if (mr->extract_type == MR_EXTRACT_BMESH) {
int l = 0;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
float fac = angle_normalized_v3v3(f->no, dir) / (float)M_PI;
float fac = angle_normalized_v3v3(bm_face_no_get(mr, f), dir) / (float)M_PI;
fac = overhang_remap(fac, min, max, minmax_irange);
for (int i = 0; i < f->len; i++, l++) {
r_overhang[l] = fac;
@@ -3385,7 +3464,11 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness)
for (int i = 0; i < mr->tri_len; i++) {
BMLoop **ltri = looptris[i];
const int index = BM_elem_index_get(ltri[0]->f);
const float *cos[3] = {ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co};
const float *cos[3] = {
bm_vert_co_get(mr, ltri[0]->v),
bm_vert_co_get(mr, ltri[1]->v),
bm_vert_co_get(mr, ltri[2]->v),
};
float ray_co[3];
float ray_no[3];
@@ -3398,7 +3481,8 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness)
BMFace *f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, &dist, NULL, NULL);
if (f_hit && dist < face_dists[index]) {
float angle_fac = fabsf(dot_v3v3(ltri[0]->f->no, f_hit->no));
float angle_fac = fabsf(
dot_v3v3(bm_face_no_get(mr, ltri[0]->f), bm_face_no_get(mr, f_hit)));
angle_fac = 1.0f - angle_fac;
angle_fac = angle_fac * angle_fac * angle_fac;
angle_fac = 1.0f - angle_fac;
@@ -3603,8 +3687,17 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort)
BMesh *bm = em->bm;
BMFace *f;
if (mr->bm_vert_coords != NULL) {
BKE_editmesh_cache_ensure_poly_normals(em, mr->edit_data);
/* Most likely this is already valid, ensure just in case.
* Needed for #BM_loop_calc_face_normal_safe_vcos. */
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
}
int l = 0;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
int p = 0;
BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, p) {
float fac = -1.0f;
if (f->len > 3) {
@@ -3613,13 +3706,23 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort)
fac = 0.0f;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
const float *no_face;
float no_corner[3];
BM_loop_calc_face_normal_safe(l_iter, no_corner);
if (mr->bm_vert_coords != NULL) {
no_face = mr->bm_poly_normals[p];
BM_loop_calc_face_normal_safe_vcos(l_iter, no_face, mr->bm_vert_coords, no_corner);
}
else {
no_face = f->no;
BM_loop_calc_face_normal_safe(l_iter, no_corner);
}
/* simple way to detect (what is most likely) concave */
if (dot_v3v3(f->no, no_corner) < 0.0f) {
if (dot_v3v3(no_face, no_corner) < 0.0f) {
negate_v3(no_corner);
}
fac = max_ff(fac, angle_normalized_v3v3(f->no, no_corner));
fac = max_ff(fac, angle_normalized_v3v3(no_face, no_corner));
} while ((l_iter = l_iter->next) != l_first);
fac *= 2.0f;
}
@@ -3842,14 +3945,14 @@ static void *extract_fdots_pos_init(const MeshRenderData *mr, void *buf)
return vbo->data;
}
static void extract_fdots_pos_loop_bmesh(const MeshRenderData *UNUSED(mr),
static void extract_fdots_pos_loop_bmesh(const MeshRenderData *mr,
int UNUSED(l),
BMLoop *loop,
void *data)
{
float(*center)[3] = (float(*)[3])data;
float w = 1.0f / (float)loop->f->len;
madd_v3_v3fl(center[BM_elem_index_get(loop->f)], loop->v->co, w);
madd_v3_v3fl(center[BM_elem_index_get(loop->f)], bm_vert_co_get(mr, loop->v), w);
}
static void extract_fdots_pos_loop_mesh(const MeshRenderData *mr,
@@ -3928,7 +4031,7 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void *
nor[f].w = NOR_AND_FLAG_HIDDEN;
}
else {
nor[f] = GPU_normal_convert_i10_v3(efa->no);
nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa));
/* Select / Active Flag. */
nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
@@ -3946,7 +4049,7 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void *
nor[f].w = NOR_AND_FLAG_HIDDEN;
}
else {
nor[f] = GPU_normal_convert_i10_v3(efa->no);
nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa));
/* Select / Active Flag. */
nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
@@ -4171,7 +4274,7 @@ static void *extract_skin_roots_init(const MeshRenderData *mr, void *buf)
const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_ofs);
if (vs->flag & MVERT_SKIN_ROOT) {
vbo_data->size = (vs->radius[0] + vs->radius[1]) * 0.5f;
copy_v3_v3(vbo_data->local_pos, eve->co);
copy_v3_v3(vbo_data->local_pos, bm_vert_co_get(mr, eve));
vbo_data++;
root_len++;
}

View File

@@ -96,11 +96,25 @@ static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *c
cd_used->edit_uv = 1;
}
BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
case ME_WRAPPER_TYPE_MDATA:
return &me->ldata;
break;
case ME_WRAPPER_TYPE_BMESH:
return &me->edit_mesh->bm->ldata;
break;
}
BLI_assert(0);
return &me->ldata;
}
static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
{
const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
const CustomData *cd_ldata = &me_final->ldata;
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
if (layer != -1) {
cd_used->uv |= (1 << layer);
@@ -110,8 +124,7 @@ static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used
static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
{
const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
const CustomData *cd_ldata = &me_final->ldata;
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
int layer = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV);
if (layer != -1) {
cd_used->uv |= (1 << layer);
@@ -121,8 +134,7 @@ static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd
static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
{
const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
const CustomData *cd_ldata = &me_final->ldata;
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL);
if (layer != -1) {
cd_used->vcol |= (1 << layer);
@@ -134,7 +146,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
int gpumat_array_len)
{
const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
const CustomData *cd_ldata = &me_final->ldata;
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
/* See: DM_vertex_attributes_from_gpu for similar logic */
DRW_MeshCDMask cd_used;

View File

@@ -374,16 +374,19 @@ static bool walk_floor_distance_get(RegionView3D *rv3d,
mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
add_v3_v3(ray_start, dvec_tmp);
ret = ED_transform_snap_object_project_ray(walk->snap_context,
walk->depsgraph,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
},
ray_start,
ray_normal,
r_distance,
r_location,
r_normal_dummy);
ret = ED_transform_snap_object_project_ray(
walk->snap_context,
walk->depsgraph,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
/* Avoid having to convert the edit-mesh to a regular mesh. */
.use_object_edit_cage = true,
},
ray_start,
ray_normal,
r_distance,
r_location,
r_normal_dummy);
/* artificially scale the distance to the scene size */
*r_distance /= walk->grid;

View File

@@ -112,7 +112,20 @@ typedef struct Mesh_Runtime {
* In the future we may leave the mesh-data empty
* since its not needed if we can use edit-mesh data. */
char is_original;
char _pad[6];
/** #eMeshWrapperType and others. */
char wrapper_type;
/**
* A type mask from wrapper_type,
* in case there are differences in finalizing logic between types.
*/
char wrapper_type_finalize;
char _pad[4];
/** Needed in case we need to lazily initialize the mesh. */
CustomData_MeshMasks cd_mask_extra;
} Mesh_Runtime;
typedef struct Mesh {
@@ -228,6 +241,15 @@ typedef struct TFace {
/* **************** MESH ********************* */
/** #Mesh_Runtime.wrapper_type */
typedef enum eMeshWrapperType {
/** Use mesh data (#Mesh.mvert,#Mesh.medge, #Mesh.mloop, #Mesh.mpoly). */
ME_WRAPPER_TYPE_MDATA = 0,
/** Use edit-mesh data (#Mesh.#edit_mesh, #Mesh_Runtime.edit_data). */
ME_WRAPPER_TYPE_BMESH = 1,
/* ME_WRAPPER_TYPE_SUBD = 2, */ /* TODO */
} eMeshWrapperType;
/* texflag */
enum {
ME_AUTOSPACE = 1,

View File

@@ -162,6 +162,11 @@ static void deformVertsEM(ModifierData *md,
ArmatureModifierData *amd = (ArmatureModifierData *)md;
Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */
armature_deform_verts(amd->object,

View File

@@ -502,10 +502,15 @@ static void deformVertsEM(ModifierData *md,
mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
}
if (mesh_src) {
if (mesh && mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
BLI_assert(mesh_src->totvert == numVerts);
}
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
if (cmd->type == MOD_CAST_TYPE_CUBOID) {
cuboid_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts);
}

View File

@@ -756,6 +756,11 @@ static void deformVertsEM(ModifierData *md,
Mesh *mesh_src = MOD_deform_mesh_eval_get(
ctx->object, editData, mesh, NULL, numVerts, false, false);
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
correctivesmooth_modifier_do(
md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, editData);

View File

@@ -142,6 +142,11 @@ static void deformVertsEM(ModifierData *md,
{
Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
deformVerts(md, ctx, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {

View File

@@ -407,6 +407,11 @@ static void deformVertsEM(ModifierData *md,
Mesh *mesh_src = MOD_deform_mesh_eval_get(
ctx->object, editData, mesh, NULL, numVerts, false, false);
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
displaceModifier_do((DisplaceModifierData *)md, ctx, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {

View File

@@ -35,6 +35,7 @@
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_runtime.h"
#include "BKE_particle.h"
@@ -783,6 +784,11 @@ static void deformVertsEM(ModifierData *md,
Mesh *mesh_src = MOD_deform_mesh_eval_get(
ctx->object, editData, mesh, NULL, numVerts, false, false);
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
LaplacianDeformModifier_do(
(LaplacianDeformModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts);

View File

@@ -559,6 +559,11 @@ static void deformVertsEM(ModifierData *md,
mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
laplaciansmoothModifier_do(
(LaplacianSmoothModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts);

View File

@@ -125,6 +125,11 @@ static void deformVertsEM(ModifierData *md,
struct Mesh *mesh_src = MOD_deform_mesh_eval_get(
ctx->object, em, mesh, NULL, numVerts, false, false);
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
deformVerts(md, ctx, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {

View File

@@ -479,6 +479,11 @@ static void deformVertsEM(ModifierData *md,
Mesh *mesh_src = MOD_deform_mesh_eval_get(
ctx->object, editData, mesh, NULL, numVerts, false, false);
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
meshdeformModifier_do(md, ctx, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {

View File

@@ -142,6 +142,11 @@ static void deformVertsEM(ModifierData *md,
mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
}
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
struct MDeformVert *dvert = NULL;
int defgrp_index = -1;
if (swmd->vgroup_name[0] != '\0') {

View File

@@ -440,6 +440,11 @@ static void deformVertsEM(ModifierData *md,
mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
}
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
SimpleDeformModifier_do(sdmd, ctx, ctx->object, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {

View File

@@ -216,6 +216,9 @@ static void deformVertsEM(ModifierData *md,
/* mesh_src is needed for vgroups, and taking edges into account. */
mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
/* TODO(campbell): use edit-mode data only (remove this line). */
BKE_mesh_wrapper_ensure_mdata(mesh_src);
smoothModifier_do(smd, ctx->object, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {

View File

@@ -196,7 +196,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
else if (ob->type == OB_MESH) {
if (em) {
mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, ob->data);
mesh = BKE_mesh_wrapper_from_editmesh_with_coords(em, NULL, vertexCos, ob->data);
}
else {
/* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether
@@ -209,9 +209,12 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
mesh->runtime.deformed_only = 1;
}
if (em != NULL) {
/* pass */
}
/* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether
* we really need vertexCos here. */
if (vertexCos) {
else if (vertexCos) {
BKE_mesh_vert_coords_apply(mesh, vertexCos);
mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
@@ -241,7 +244,9 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
}
BLI_assert(mesh == NULL || mesh->totvert == num_verts);
if (mesh && mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
BLI_assert(mesh->totvert == num_verts);
}
return mesh;
}

View File

@@ -381,6 +381,11 @@ static void deformVertsEM(ModifierData *md,
mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
}
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {

View File

@@ -353,6 +353,11 @@ static void deformVertsEM(ModifierData *md,
mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
}
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
waveModifier_do(wmd, ctx, ctx->object, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {