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:
@@ -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. */
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
165
source/blender/blenkernel/intern/mesh_wrapper.c
Normal file
165
source/blender/blenkernel/intern/mesh_wrapper.c
Normal 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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user