Fix T48290: Hook fails after deleting geometry

Now CD_SHAPEKEY_INDEX customdata is stored in edit-mode when hooks and vertex parents are used.

This also fixes a bug where undo would loose key-index data.

Move to structs for BM_mesh_bm_to/from_me to avoid passing many argument, which mostly aren't used.
This commit is contained in:
Campbell Barton 2016-04-29 22:33:06 +10:00
parent b5ce2bbef7
commit 6d0cae56e8
Notes: blender-bot 2023-02-14 07:56:12 +01:00
Referenced by issue #48290, Hooks no longer working if some parts of the mesh are removed
20 changed files with 121 additions and 49 deletions

View File

@ -69,7 +69,7 @@ extern "C" {
/* *** mesh.c *** */
struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob);
struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob, const bool add_key_index);
int poly_find_loop_from_vert(
const struct MPoly *poly,

View File

@ -595,14 +595,17 @@ Mesh *BKE_mesh_copy(Mesh *me)
return BKE_mesh_copy_ex(G.main, me);
}
BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob)
BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob, const bool add_key_index)
{
BMesh *bm;
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
bm = BM_mesh_create(&allocsize);
BM_mesh_bm_from_me(bm, me, false, true, ob->shapenr);
BM_mesh_bm_from_me(
bm, me, (&(struct BMeshFromMeshParams){
.add_key_index = add_key_index, .use_shapekey = true, .active_shapekey = ob->shapenr,
}));
return bm;
}

View File

@ -635,7 +635,7 @@ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
}
if (reorder)
BM_log_mesh_elems_reorder(ss->bm, ss->bm_log);
BM_mesh_bm_to_me(ss->bm, ob->data, false);
BM_mesh_bm_to_me(ss->bm, ob->data, (&(struct BMeshToMeshParams){0}));
}
}
}

View File

@ -1774,7 +1774,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
{
if (check_rendered_viewport_visible(bmain)) {
BMesh *bm = mesh->edit_btmesh->bm;
BM_mesh_bm_to_me(bm, mesh, false);
BM_mesh_bm_to_me(bm, mesh, (&(struct BMeshToMeshParams){0}));
DAG_id_tag_update(&mesh->id, 0);
}
}

View File

@ -224,7 +224,7 @@ static BMFace *bm_face_create_from_mpoly(
*/
void BM_mesh_bm_from_me(
BMesh *bm, Mesh *me,
const bool calc_face_normal, const bool set_key, int act_key_nr)
const struct BMeshFromMeshParams *params)
{
MVert *mvert;
MEdge *medge;
@ -273,8 +273,8 @@ void BM_mesh_bm_from_me(
CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name);
}
if ((act_key_nr != 0) && (me->key != NULL)) {
actkey = BLI_findlink(&me->key->block, act_key_nr - 1);
if ((params->active_shapekey != 0) && (me->key != NULL)) {
actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1);
}
else {
actkey = NULL;
@ -283,9 +283,11 @@ void BM_mesh_bm_from_me(
const int tot_shape_keys = me->key ? BLI_listbase_count(&me->key->block) : 0;
const float (**shape_key_table)[3] = tot_shape_keys ? BLI_array_alloca(shape_key_table, tot_shape_keys) : NULL;
if (tot_shape_keys) {
if (tot_shape_keys || params->add_key_index) {
CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
}
if (tot_shape_keys) {
/* check if we need to generate unique ids for the shapekeys.
* this also exists in the file reading code, but is here for
* a sanity check */
@ -303,7 +305,7 @@ void BM_mesh_bm_from_me(
if (actkey && actkey->totelem == me->totvert) {
keyco = actkey->data;
bm->shapenr = act_key_nr;
bm->shapenr = params->active_shapekey;
}
for (i = 0, block = me->key->block.first; block; block = block->next, i++) {
@ -328,10 +330,13 @@ void BM_mesh_bm_from_me(
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
const int cd_shape_key_offset = me->key ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) : -1;
const int cd_shape_keyindex_offset = me->key ? CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) : -1;
const int cd_shape_keyindex_offset = (tot_shape_keys || params->add_key_index) ?
CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) : -1;
for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
v = vtable[i] = BM_vert_create(bm, keyco && set_key ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD);
v = vtable[i] = BM_vert_create(
bm, keyco && params->use_shapekey ? keyco[i] : mvert->co, NULL,
BM_CREATE_SKIP_CD);
BM_elem_index_set(v, i); /* set_ok */
/* transfer flag */
@ -349,11 +354,11 @@ void BM_mesh_bm_from_me(
if (cd_vert_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert->bweight / 255.0f);
/* set shape key original index */
if (cd_shape_keyindex_offset != -1) BM_ELEM_CD_SET_INT(v, cd_shape_keyindex_offset, i);
/* set shapekey data */
if (tot_shape_keys) {
/* set shape key original index */
if (cd_shape_keyindex_offset != -1) BM_ELEM_CD_SET_INT(v, cd_shape_keyindex_offset, i);
float (*co_dst)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset);
for (j = 0; j < tot_shape_keys; j++, co_dst++) {
copy_v3_v3(*co_dst, shape_key_table[j][i]);
@ -436,7 +441,7 @@ void BM_mesh_bm_from_me(
/* Copy Custom Data */
CustomData_to_bmesh_block(&me->pdata, &bm->pdata, i, &f->head.data, true);
if (calc_face_normal) {
if (params->calc_face_normal) {
BM_face_normal_update(f);
}
}
@ -571,7 +576,9 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
}
}
void BM_mesh_bm_to_me(BMesh *bm, Mesh *me, bool do_tessface)
void BM_mesh_bm_to_me(
BMesh *bm, Mesh *me,
const struct BMeshToMeshParams *params)
{
MLoop *mloop;
MPoly *mpoly;
@ -632,10 +639,13 @@ void BM_mesh_bm_to_me(BMesh *bm, Mesh *me, bool do_tessface)
me->totface = 0;
me->act_face = -1;
CustomData_copy(&bm->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert);
CustomData_copy(&bm->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge);
CustomData_copy(&bm->ldata, &me->ldata, CD_MASK_MESH, CD_CALLOC, me->totloop);
CustomData_copy(&bm->pdata, &me->pdata, CD_MASK_MESH, CD_CALLOC, me->totpoly);
{
const CustomDataMask mask = CD_MASK_MESH | params->cd_mask_extra;
CustomData_copy(&bm->vdata, &me->vdata, mask, CD_CALLOC, me->totvert);
CustomData_copy(&bm->edata, &me->edata, mask, CD_CALLOC, me->totedge);
CustomData_copy(&bm->ldata, &me->ldata, mask, CD_CALLOC, me->totloop);
CustomData_copy(&bm->pdata, &me->pdata, mask, CD_CALLOC, me->totpoly);
}
CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
@ -784,11 +794,11 @@ void BM_mesh_bm_to_me(BMesh *bm, Mesh *me, bool do_tessface)
if (vertMap) MEM_freeN(vertMap);
}
if (do_tessface) {
if (params->calc_tessface) {
BKE_mesh_tessface_calc(me);
}
BKE_mesh_update_customdata_pointers(me, do_tessface);
BKE_mesh_update_customdata_pointers(me, params->calc_tessface);
{
BMEditSelection *selected;

View File

@ -39,9 +39,28 @@ void BM_mesh_cd_flag_ensure(BMesh *bm, struct Mesh *mesh, const char cd_flag);
void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag);
char BM_mesh_cd_flag_from_bmesh(BMesh *bm);
struct BMeshFromMeshParams {
unsigned int calc_face_normal : 1;
/* add a vertex CD_SHAPE_KEYINDEX layer */
unsigned int add_key_index : 1;
/* set vertex coordinates from the shapekey */
unsigned int use_shapekey : 1;
/* define the active shape key (index + 1) */
int active_shapekey;
};
void BM_mesh_bm_from_me(
BMesh *bm, struct Mesh *me,
const bool calc_face_normal, const bool set_key, int act_key_nr);
void BM_mesh_bm_to_me(BMesh *bm, struct Mesh *me, bool do_tessface);
const struct BMeshFromMeshParams *params)
ATTR_NONNULL(1, 2, 3);
struct BMeshToMeshParams {
unsigned int calc_tessface : 1;
int64_t cd_mask_extra;
};
void BM_mesh_bm_to_me(
BMesh *bm, struct Mesh *me,
const struct BMeshToMeshParams *params)
ATTR_NONNULL(1, 2, 3);
#endif /* __BMESH_MESH_CONV_H__ */

View File

@ -45,7 +45,10 @@ void bmo_mesh_to_bmesh_exec(BMesh *bm, BMOperator *op)
Mesh *me = BMO_slot_ptr_get(op->slots_in, "mesh");
bool set_key = BMO_slot_bool_get(op->slots_in, "use_shapekey");
BM_mesh_bm_from_me(bm, me, false, set_key, ob->shapenr);
BM_mesh_bm_from_me(
bm, me, (&(struct BMeshFromMeshParams){
.use_shapekey = set_key, .active_shapekey = ob->shapenr,
}));
if (me->key && ob->shapenr > me->key->totkey) {
ob->shapenr = me->key->totkey - 1;
@ -69,5 +72,5 @@ void bmo_bmesh_to_mesh_exec(BMesh *bm, BMOperator *op)
/* Object *ob = BMO_slot_ptr_get(op, "object"); */
const bool dotess = !BMO_slot_bool_get(op->slots_in, "skip_tessface");
BM_mesh_bm_to_me(bm, me, dotess);
BM_mesh_bm_to_me(bm, me, (&(struct BMeshToMeshParams){ .calc_tessface = dotess, }));
}

View File

@ -80,7 +80,7 @@ void EDBM_mesh_normals_update(struct BMEditMesh *em);
void EDBM_mesh_clear(struct BMEditMesh *em);
void EDBM_selectmode_to_scene(struct bContext *C);
void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob);
void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob, const bool add_key_index);
void EDBM_mesh_free(struct BMEditMesh *em);
void EDBM_mesh_load(struct Object *ob);
struct DerivedMesh *EDBM_mesh_deform_dm_get(struct BMEditMesh *em);

View File

@ -3011,7 +3011,7 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe
BM_mesh_normals_update(bm_new);
BM_mesh_bm_to_me(bm_new, base_new->object->data, false);
BM_mesh_bm_to_me(bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0}));
BM_mesh_free(bm_new);
((Mesh *)base_new->object->data)->edit_btmesh = NULL;
@ -3294,7 +3294,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
bm_old = BM_mesh_create(&bm_mesh_allocsize_default);
BM_mesh_bm_from_me(bm_old, me, false, false, 0);
BM_mesh_bm_from_me(bm_old, me, (&(struct BMeshFromMeshParams){0}));
switch (type) {
case MESH_SEPARATE_MATERIAL:
@ -3309,7 +3309,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
}
if (retval_iter) {
BM_mesh_bm_to_me(bm_old, me, false);
BM_mesh_bm_to_me(bm_old, me, (&(struct BMeshToMeshParams){0}));
DAG_id_tag_update(&me->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);

View File

@ -347,7 +347,7 @@ void EDBM_selectmode_to_scene(bContext *C)
WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene);
}
void EDBM_mesh_make(ToolSettings *ts, Object *ob)
void EDBM_mesh_make(ToolSettings *ts, Object *ob, const bool add_key_index)
{
Mesh *me = ob->data;
BMesh *bm;
@ -356,7 +356,7 @@ void EDBM_mesh_make(ToolSettings *ts, Object *ob)
BKE_mesh_convert_mfaces_to_mpolys(me);
}
bm = BKE_mesh_to_bmesh(me, ob);
bm = BKE_mesh_to_bmesh(me, ob, add_key_index);
if (me->edit_btmesh) {
/* this happens when switching shape keys */
@ -395,7 +395,7 @@ void EDBM_mesh_load(Object *ob)
bm->shapenr = 1;
}
BM_mesh_bm_to_me(bm, me, false);
BM_mesh_bm_to_me(bm, me, (&(struct BMeshToMeshParams){0}));
#ifdef USE_TESSFACE_DEFAULT
BKE_mesh_tessface_calc(me);
@ -533,7 +533,10 @@ static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
/* BM_mesh_validate(em->bm); */ /* for troubleshooting */
BM_mesh_bm_to_me(em->bm, &um->me, false);
BM_mesh_bm_to_me(
em->bm, &um->me, (&(struct BMeshToMeshParams){
.cd_mask_extra = CD_MASK_SHAPE_KEYINDEX,
}));
um->selectmode = em->selectmode;
um->shapenr = em->bm->shapenr;
@ -557,7 +560,10 @@ static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *obdata)
bm = BM_mesh_create(&allocsize);
BM_mesh_bm_from_me(bm, &um->me, true, false, um->shapenr);
BM_mesh_bm_from_me(
bm, &um->me, (&(struct BMeshFromMeshParams){
.calc_face_normal = true, .active_shapekey = um->shapenr,
}));
em_tmp = BKE_editmesh_create(bm, true);
*em = *em_tmp;

View File

@ -582,7 +582,7 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *e
obedit = base->object;
me = obedit->data;
if (me->edit_btmesh == NULL) {
EDBM_mesh_make(scene->toolsettings, obedit);
EDBM_mesh_make(scene->toolsettings, obedit, false);
exitmode = 1;
}
if (me->edit_btmesh == NULL)

View File

@ -572,7 +572,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
#else
/* toggle editmode using lower level functions so this can be called from python */
EDBM_mesh_make(scene->toolsettings, ob);
EDBM_mesh_make(scene->toolsettings, ob, false);
EDBM_mesh_load(ob);
EDBM_mesh_free(me->edit_btmesh);
MEM_freeN(me->edit_btmesh);

View File

@ -316,6 +316,27 @@ void OBJECT_OT_hide_render_set(wmOperatorType *ot)
/* ******************* toggle editmode operator ***************** */
static bool mesh_needs_keyindex(const Mesh *me)
{
if (me->key) {
return false; /* will be added */
}
for (const Object *ob = G.main->object.first; ob; ob = ob->id.next) {
if ((ob->parent) && (ob->parent->data == me) && ELEM(ob->partype, PARVERT1, PARVERT3)) {
return true;
}
if (ob->data == me) {
for (const ModifierData *md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Hook) {
return true;
}
}
}
}
return false;
}
/**
* Load EditMode data back into the object,
* optionally freeing the editmode data.
@ -494,7 +515,9 @@ void ED_object_editmode_enter(bContext *C, int flag)
ok = 1;
scene->obedit = ob; /* context sees this */
EDBM_mesh_make(scene->toolsettings, ob);
const bool use_key_index = mesh_needs_keyindex(ob->data);
EDBM_mesh_make(scene->toolsettings, ob, use_key_index);
em = BKE_editmesh_from_object(ob);
if (LIKELY(em)) {

View File

@ -316,7 +316,7 @@ static bool object_hook_index_array(Scene *scene, Object *obedit,
BMEditMesh *em;
EDBM_mesh_load(obedit);
EDBM_mesh_make(scene->toolsettings, obedit);
EDBM_mesh_make(scene->toolsettings, obedit, true);
DAG_id_tag_update(obedit->data, 0);

View File

@ -136,7 +136,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
BMEditMesh *em;
EDBM_mesh_load(obedit);
EDBM_mesh_make(scene->toolsettings, obedit);
EDBM_mesh_make(scene->toolsettings, obedit, true);
DAG_id_tag_update(obedit->data, 0);

View File

@ -5866,15 +5866,17 @@ static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
ED_mesh_uv_texture_ensure(me, NULL);
BM_mesh_bm_from_me(bm, me, true, false, 0);
BM_mesh_bm_from_me(
bm, me,(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
}));
/* select all uv loops first - pack parameters needs this to make sure charts are registered */
ED_uvedit_select_all(bm);
ED_uvedit_unwrap_cube_project(ob, bm, 1.0, false);
/* set the margin really quickly before the packing operation*/
scene->toolsettings->uvcalc_margin = 0.001f;
ED_uvedit_pack_islands(scene, ob, bm, false, false, true);
BM_mesh_bm_to_me(bm, me, false);
BM_mesh_bm_to_me(bm, me, (&(struct BMeshToMeshParams){0}));
BM_mesh_free(bm);
if (synch_selection)

View File

@ -5003,7 +5003,10 @@ void sculpt_dynamic_topology_enable(bContext *C)
/* Create triangles-only BMesh */
ss->bm = BM_mesh_create(&allocsize);
BM_mesh_bm_from_me(ss->bm, me, true, true, ob->shapenr);
BM_mesh_bm_from_me(
ss->bm, me, (&(struct BMeshFromMeshParams){
.calc_face_normal = true, .use_shapekey = true, .active_shapekey = ob->shapenr,
}));
sculpt_dynamic_topology_triangulate(ss->bm);
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
sculpt_dyntopo_node_layers_add(ss);

View File

@ -267,7 +267,7 @@ static void rna_Object_active_shape_update(Main *bmain, Scene *scene, PointerRNA
switch (ob->type) {
case OB_MESH:
EDBM_mesh_load(ob);
EDBM_mesh_make(scene->toolsettings, ob);
EDBM_mesh_make(scene->toolsettings, ob, true);
DAG_id_tag_update(ob->data, 0);

View File

@ -916,7 +916,7 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
/* python won't ensure matching uv/mtex */
BM_mesh_cd_validate(bm);
BM_mesh_bm_to_me(bm, me, false);
BM_mesh_bm_to_me(bm, me, (&(struct BMeshToMeshParams){0}));
/* we could have the user do this but if they forget blender can easy crash
* since the references arrays for the objects derived meshes are now invalid */
@ -1075,7 +1075,10 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *
bm = self->bm;
BM_mesh_bm_from_me(bm, me, use_fnorm, use_shape_key, shape_key_index + 1);
BM_mesh_bm_from_me(
bm, me, (&(struct BMeshFromMeshParams){
.calc_face_normal = use_fnorm, .use_shapekey = use_shape_key, .active_shapekey = shape_key_index + 1,
}));
Py_RETURN_NONE;
}

View File

@ -221,7 +221,7 @@ bool BPY_string_is_keyword(const char *str) { return false; }
/*new render funcs */
void EDBM_selectmode_set(struct BMEditMesh *em) RET_NONE
void EDBM_mesh_load(struct Object *ob) RET_NONE
void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob) RET_NONE
void EDBM_mesh_make(struct ToolSettings *ts, struct Object *ob, const bool use_key_index) RET_NONE
void EDBM_mesh_normals_update(struct BMEditMesh *em) RET_NONE
void *g_system;
bool EDBM_mtexpoly_check(struct BMEditMesh *em) RET_ZERO