Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/object/object_edit.c
| Show First 20 Lines • Show All 514 Lines • ▼ Show 20 Lines | if (ob->data == me) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /** | /** | ||||
| * Load EditMode data back into the object, | * Load edit-mode data back into the object. | ||||
| * optionally freeing the editmode data. | * | ||||
| * \param load_data: Flush the edit-mode data back to the object. | |||||
| * \param free_data: Free the edit-mode data. | |||||
| */ | */ | ||||
| static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool freedata) | static bool ED_object_editmode_load_free_ex(Main *bmain, | ||||
| Object *obedit, | |||||
| const bool load_data, | |||||
| const bool free_data) | |||||
| { | { | ||||
| BLI_assert(load_data || free_data); | |||||
| if (obedit == NULL) { | if (obedit == NULL) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (obedit->type == OB_MESH) { | if (obedit->type == OB_MESH) { | ||||
| Mesh *me = obedit->data; | Mesh *me = obedit->data; | ||||
| if (me->edit_mesh == NULL) { | if (me->edit_mesh == NULL) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (me->edit_mesh->bm->totvert > MESH_MAX_VERTS) { | if (me->edit_mesh->bm->totvert > MESH_MAX_VERTS) { | ||||
| /* This used to be warned int the UI, we could warn again although it's quite rare. */ | /* This used to be warned int the UI, we could warn again although it's quite rare. */ | ||||
| CLOG_WARN(&LOG, | CLOG_WARN(&LOG, | ||||
| "Too many vertices for mesh '%s' (%d)", | "Too many vertices for mesh '%s' (%d)", | ||||
| me->id.name + 2, | me->id.name + 2, | ||||
| me->edit_mesh->bm->totvert); | me->edit_mesh->bm->totvert); | ||||
| return false; | return false; | ||||
| } | } | ||||
| EDBM_mesh_load_ex(bmain, obedit, freedata); | if (load_data) { | ||||
| EDBM_mesh_load_ex(bmain, obedit, free_data); | |||||
| } | |||||
| if (freedata) { | if (free_data) { | ||||
| EDBM_mesh_free(me->edit_mesh); | EDBM_mesh_free(me->edit_mesh); | ||||
| MEM_freeN(me->edit_mesh); | MEM_freeN(me->edit_mesh); | ||||
| me->edit_mesh = NULL; | me->edit_mesh = NULL; | ||||
| } | } | ||||
| /* will be recalculated as needed. */ | /* will be recalculated as needed. */ | ||||
| { | { | ||||
| ED_mesh_mirror_spatial_table_end(obedit); | ED_mesh_mirror_spatial_table_end(obedit); | ||||
| ED_mesh_mirror_topo_table_end(obedit); | ED_mesh_mirror_topo_table_end(obedit); | ||||
| } | } | ||||
| } | } | ||||
| else if (obedit->type == OB_ARMATURE) { | else if (obedit->type == OB_ARMATURE) { | ||||
| const bArmature *arm = obedit->data; | const bArmature *arm = obedit->data; | ||||
| if (arm->edbo == NULL) { | if (arm->edbo == NULL) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (load_data) { | |||||
| ED_armature_from_edit(bmain, obedit->data); | ED_armature_from_edit(bmain, obedit->data); | ||||
| if (freedata) { | } | ||||
| if (free_data) { | |||||
| ED_armature_edit_free(obedit->data); | ED_armature_edit_free(obedit->data); | ||||
| } | } | ||||
| /* TODO(sergey): Pose channels might have been changed, so need | /* TODO(sergey): Pose channels might have been changed, so need | ||||
| * to inform dependency graph about this. But is it really the | * to inform dependency graph about this. But is it really the | ||||
| * best place to do this? | * best place to do this? | ||||
| */ | */ | ||||
| DEG_relations_tag_update(bmain); | DEG_relations_tag_update(bmain); | ||||
| } | } | ||||
| else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { | else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { | ||||
| const Curve *cu = obedit->data; | const Curve *cu = obedit->data; | ||||
| if (cu->editnurb == NULL) { | if (cu->editnurb == NULL) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (load_data) { | |||||
| ED_curve_editnurb_load(bmain, obedit); | ED_curve_editnurb_load(bmain, obedit); | ||||
| if (freedata) { | } | ||||
| if (free_data) { | |||||
| ED_curve_editnurb_free(obedit); | ED_curve_editnurb_free(obedit); | ||||
| } | } | ||||
| } | } | ||||
| else if (obedit->type == OB_FONT) { | else if (obedit->type == OB_FONT) { | ||||
| const Curve *cu = obedit->data; | const Curve *cu = obedit->data; | ||||
| if (cu->editfont == NULL) { | if (cu->editfont == NULL) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (load_data) { | |||||
| ED_curve_editfont_load(obedit); | ED_curve_editfont_load(obedit); | ||||
| if (freedata) { | } | ||||
| if (free_data) { | |||||
| ED_curve_editfont_free(obedit); | ED_curve_editfont_free(obedit); | ||||
| } | } | ||||
| } | } | ||||
| else if (obedit->type == OB_LATTICE) { | else if (obedit->type == OB_LATTICE) { | ||||
| const Lattice *lt = obedit->data; | const Lattice *lt = obedit->data; | ||||
| if (lt->editlatt == NULL) { | if (lt->editlatt == NULL) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (load_data) { | |||||
| BKE_editlattice_load(obedit); | BKE_editlattice_load(obedit); | ||||
| if (freedata) { | } | ||||
| if (free_data) { | |||||
| BKE_editlattice_free(obedit); | BKE_editlattice_free(obedit); | ||||
| } | } | ||||
| } | } | ||||
| else if (obedit->type == OB_MBALL) { | else if (obedit->type == OB_MBALL) { | ||||
| const MetaBall *mb = obedit->data; | const MetaBall *mb = obedit->data; | ||||
| if (mb->editelems == NULL) { | if (mb->editelems == NULL) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (load_data) { | |||||
| ED_mball_editmball_load(obedit); | ED_mball_editmball_load(obedit); | ||||
| if (freedata) { | } | ||||
| if (free_data) { | |||||
| ED_mball_editmball_free(obedit); | ED_mball_editmball_free(obedit); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (load_data) { | |||||
| char *needs_flush_ptr = BKE_object_data_editmode_flush_ptr_get(obedit->data); | char *needs_flush_ptr = BKE_object_data_editmode_flush_ptr_get(obedit->data); | ||||
| if (needs_flush_ptr) { | if (needs_flush_ptr) { | ||||
| *needs_flush_ptr = false; | *needs_flush_ptr = false; | ||||
| } | } | ||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| bool ED_object_editmode_load(Main *bmain, Object *obedit) | bool ED_object_editmode_load(Main *bmain, Object *obedit) | ||||
| { | { | ||||
| return ED_object_editmode_load_ex(bmain, obedit, false); | return ED_object_editmode_load_free_ex(bmain, obedit, true, false); | ||||
| } | } | ||||
| /** | /** | ||||
| * \param flag: | * \param flag: | ||||
| * - If #EM_FREEDATA isn't in the flag, use ED_object_editmode_load directly. | * - If #EM_FREEDATA isn't in the flag, use ED_object_editmode_load directly. | ||||
| */ | */ | ||||
| bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int flag) | bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int flag) | ||||
| { | { | ||||
| const bool freedata = (flag & EM_FREEDATA) != 0; | const bool free_data = (flag & EM_FREEDATA) != 0; | ||||
| if (ED_object_editmode_load_ex(bmain, obedit, freedata) == false) { | if (ED_object_editmode_load_free_ex(bmain, obedit, true, free_data) == false) { | ||||
| /* in rare cases (background mode) its possible active object | /* in rare cases (background mode) its possible active object | ||||
| * is flagged for editmode, without 'obedit' being set T35489. */ | * is flagged for editmode, without 'obedit' being set T35489. */ | ||||
| if (UNLIKELY(obedit && obedit->mode & OB_MODE_EDIT)) { | if (UNLIKELY(obedit && obedit->mode & OB_MODE_EDIT)) { | ||||
| obedit->mode &= ~OB_MODE_EDIT; | obedit->mode &= ~OB_MODE_EDIT; | ||||
| /* Also happens when mesh is shared across multiple objects. [#T69834] */ | /* Also happens when mesh is shared across multiple objects. [#T69834] */ | ||||
| DEG_id_tag_update(&obedit->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); | DEG_id_tag_update(&obedit->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* freedata only 0 now on file saves and render */ | /* `free_data` only false now on file saves and render. */ | ||||
| if (freedata) { | if (free_data) { | ||||
| /* flag object caches as outdated */ | /* flag object caches as outdated */ | ||||
| ListBase pidlist; | ListBase pidlist; | ||||
| BKE_ptcache_ids_from_object(&pidlist, obedit, scene, 0); | BKE_ptcache_ids_from_object(&pidlist, obedit, scene, 0); | ||||
| LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) { | LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) { | ||||
| /* particles don't need reset on geometry change */ | /* particles don't need reset on geometry change */ | ||||
| if (pid->type != PTCACHE_TYPE_PARTICLES) { | if (pid->type != PTCACHE_TYPE_PARTICLES) { | ||||
| pid->cache->flag |= PTCACHE_OUTDATED; | pid->cache->flag |= PTCACHE_OUTDATED; | ||||
| } | } | ||||
| Show All 17 Lines | |||||
| bool ED_object_editmode_exit(bContext *C, int flag) | bool ED_object_editmode_exit(bContext *C, int flag) | ||||
| { | { | ||||
| Main *bmain = CTX_data_main(C); | Main *bmain = CTX_data_main(C); | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| Object *obedit = CTX_data_edit_object(C); | Object *obedit = CTX_data_edit_object(C); | ||||
| return ED_object_editmode_exit_ex(bmain, scene, obedit, flag); | return ED_object_editmode_exit_ex(bmain, scene, obedit, flag); | ||||
| } | } | ||||
| /** | |||||
| * Support freeing edit-mode data without flushing it back to the object. | |||||
| * | |||||
| * \return true if data was freed. | |||||
| */ | |||||
| bool ED_object_editmode_free_ex(Main *bmain, Object *obedit) | |||||
| { | |||||
| return ED_object_editmode_load_free_ex(bmain, obedit, false, true); | |||||
| } | |||||
| bool ED_object_editmode_exit_multi_ex(Main *bmain, Scene *scene, ViewLayer *view_layer, int flag) | bool ED_object_editmode_exit_multi_ex(Main *bmain, Scene *scene, ViewLayer *view_layer, int flag) | ||||
| { | { | ||||
| Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); | Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); | ||||
| if (obedit == NULL) { | if (obedit == NULL) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| bool changed = false; | bool changed = false; | ||||
| const short obedit_type = obedit->type; | const short obedit_type = obedit->type; | ||||
| Show All 19 Lines | |||||
| { | { | ||||
| bool ok = false; | bool ok = false; | ||||
| if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED(ob) || ID_IS_OVERRIDE_LIBRARY(ob) || | if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED(ob) || ID_IS_OVERRIDE_LIBRARY(ob) || | ||||
| ID_IS_OVERRIDE_LIBRARY(ob->data)) { | ID_IS_OVERRIDE_LIBRARY(ob->data)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* This checks actual `ob->data`, for cases when other scenes have it in edit-mode context. | |||||
| * Currently multiple objects sharing a mesh being in edit-mode at once isn't supported, | |||||
| * see: T86767. */ | |||||
| if (BKE_object_is_in_editmode(ob)) { | |||||
| return true; | |||||
| } | |||||
| if (BKE_object_obdata_is_libdata(ob)) { | if (BKE_object_obdata_is_libdata(ob)) { | ||||
| /* Ideally the caller should check this. */ | /* Ideally the caller should check this. */ | ||||
| CLOG_WARN(&LOG, "Unable to enter edit-mode on library data for object '%s'", ob->id.name + 2); | CLOG_WARN(&LOG, "Unable to enter edit-mode on library data for object '%s'", ob->id.name + 2); | ||||
| return false; | return false; | ||||
| } | } | ||||
| if ((ob->mode & OB_MODE_EDIT) == 0) { | |||||
| ob->restore_mode = ob->mode; | ob->restore_mode = ob->mode; | ||||
| ob->mode = OB_MODE_EDIT; | ob->mode = OB_MODE_EDIT; | ||||
| } | |||||
| /* This checks actual `object->data`, | |||||
| * for cases when other scenes have it in edit-mode context. | |||||
| * | |||||
| * It's important to run this after setting the object's mode (above), since in rare cases | |||||
| * the object may have the edit-data but not it's object-mode set. See T85974. */ | |||||
| if (BKE_object_is_in_editmode(ob)) { | |||||
| return true; | |||||
| } | |||||
| if (ob->type == OB_MESH) { | if (ob->type == OB_MESH) { | ||||
| ok = true; | ok = true; | ||||
| const bool use_key_index = mesh_needs_keyindex(bmain, ob->data); | const bool use_key_index = mesh_needs_keyindex(bmain, ob->data); | ||||
| EDBM_mesh_make(ob, scene->toolsettings->selectmode, use_key_index); | EDBM_mesh_make(ob, scene->toolsettings->selectmode, use_key_index); | ||||
| ▲ Show 20 Lines • Show All 1,326 Lines • Show Last 20 Lines | |||||