diff options
95 files changed, 1583 insertions, 1508 deletions
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 6524afff051..772e08589c1 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -62,7 +62,7 @@ struct AnimData *BKE_animdata_add_id(struct ID *id); bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act); /* Free AnimData */ -void BKE_animdata_free(struct ID *id); +void BKE_animdata_free(struct ID *id, const bool do_id_user); /* Copy AnimData */ struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action); diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 061270b8b41..23b3128f328 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -66,7 +66,6 @@ typedef struct CurveCache { #define CU_DO_2DFILL(cu) ((((cu)->flag & CU_3D) == 0) && (((cu)->flag & (CU_FRONT | CU_BACK)) != 0)) /* ** Curve ** */ -void BKE_curve_unlink(struct Curve *cu); void BKE_curve_free(struct Curve *cu); void BKE_curve_editfont_free(struct Curve *cu); void BKE_curve_init(struct Curve *cu); diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h index 9056e48cf50..ae6e52b613b 100644 --- a/source/blender/blenkernel/BKE_group.h +++ b/source/blender/blenkernel/BKE_group.h @@ -41,7 +41,6 @@ struct Object; struct Scene; void BKE_group_free(struct Group *group); -void BKE_group_unlink(struct Main *bmain, struct Group *group); struct Group *BKE_group_add(struct Main *bmain, const char *name); struct Group *BKE_group_copy(struct Group *group); bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 2215fbfbd7d..56f040ab260 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -60,13 +60,15 @@ void BKE_libblock_relink(struct ID *id); void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL(); void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL(); +struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); + +/* library_remap.c (keep here since they're general functions) */ void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_libblock_free_ex(struct Main *bmain, void *idv, bool do_id_user) ATTR_NONNULL(); void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_libblock_free_data(struct Main *bmain, struct ID *id) ATTR_NONNULL(); - -struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id); void id_lib_extern(struct ID *id); @@ -82,7 +84,6 @@ void id_fake_user_clear(struct ID *id); bool id_make_local(struct ID *id, bool test); bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop); bool id_copy(struct ID *id, struct ID **newid, bool test); -bool id_unlink(struct ID *id, int test); void id_sort_by_name(struct ListBase *lb, struct ID *id); bool new_id(struct ListBase *lb, struct ID *id, const char *name); @@ -119,16 +120,11 @@ void BKE_main_lib_objects_recalc_all(struct Main *bmain); /* (MAX_ID_NAME - 2) + 3 */ void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id); +void BKE_library_free(struct Library *lib); + void BKE_library_make_local( struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake); -typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *); -typedef void (*BKE_library_free_notifier_reference_cb)(const void *); -typedef void (*BKE_library_free_editor_id_reference_cb)(const struct ID *); - -void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func); -void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func); -void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func); /* use when "" is given to new_id() */ #define ID_FALLBACK_NAME N_("Untitled") diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h index 2e73be576f9..c89dce99caa 100644 --- a/source/blender/blenkernel/BKE_library_query.h +++ b/source/blender/blenkernel/BKE_library_query.h @@ -32,6 +32,7 @@ */ struct ID; +struct Main; /* Tips for the callback for cases it's gonna to modify the pointer. */ enum { diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h new file mode 100644 index 00000000000..e85a3e60751 --- /dev/null +++ b/source/blender/blenkernel/BKE_library_remap.h @@ -0,0 +1,76 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_LIBRARY_REMAP_H__ +#define __BKE_LIBRARY_REMAP_H__ + +/** \file BKE_library_remap.h + * \ingroup bke + */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "BLI_compiler_attrs.h" + +/* BKE_libblock_free, delete are declared in BKE_library.h for convenience. */ + +/* Also IDRemap->flag. */ +enum { + /* Do not remap indirect usages of IDs (that is, when user is some linked data). */ + ID_REMAP_SKIP_INDIRECT_USAGE = 1 << 0, + /* This flag should always be set, *except for 'unlink' scenarios* (only relevant when new_id == NULL). + * Basically, when unset, NEVER_NULL ID usages will keep pointing to old_id, but (if needed) old_id user count + * will still be decremented. This is mandatory for 'delete ID' case, but in all other situation this would lead + * to invalid user counts! */ + ID_REMAP_SKIP_NEVER_NULL_USAGE = 1 << 1, + /* This tells the callback func to flag with LIB_DOIT all IDs using target one with a 'never NULL' pointer + * (like e.g. Object->data). */ + ID_REMAP_FLAG_NEVER_NULL_USAGE = 1 << 2, + /* This tells the callback func to force setting IDs using target one with a 'never NULL' pointer to NULL. + * WARNING! Use with extreme care, this will leave database in broken state! */ + ID_REMAP_FORCE_NEVER_NULL_USAGE = 1 << 3, +}; + +/* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, but makes things simpler for now. */ +void BKE_libblock_remap_locked( + struct Main *bmain, void *old_idv, void *new_idv, + const short remap_flags) ATTR_NONNULL(1, 2); +void BKE_libblock_remap( + struct Main *bmain, void *old_idv, void *new_idv, + const short remap_flags) ATTR_NONNULL(1, 2); + +void BKE_libblock_unlink(struct Main *bmain, void *idv, const bool do_flag_never_null) ATTR_NONNULL(); + +void BKE_libblock_relink_ex(void *idv, void *old_idv, void *new_idv, const bool us_min_never_null) ATTR_NONNULL(1); + + +typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *); +typedef void (*BKE_library_free_notifier_reference_cb)(const void *); +typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *); + +void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func); +void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func); +void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func); + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_LIBRARY_REMAP_H__ */
\ No newline at end of file diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h index e3eead4102c..e343cd29622 100644 --- a/source/blender/blenkernel/BKE_linestyle.h +++ b/source/blender/blenkernel/BKE_linestyle.h @@ -79,8 +79,6 @@ void BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineSty void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase); char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, struct ColorBand *color_ramp); -void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob); - bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes); void BKE_linestyle_default_shader(const struct bContext *C, FreestyleLineStyle *linestyle); diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index 25893d54dca..f3d12b5a8cc 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -125,8 +125,7 @@ struct Mask *BKE_mask_new(struct Main *bmain, const char *name); struct Mask *BKE_mask_copy_nolib(struct Mask *mask); struct Mask *BKE_mask_copy(struct Mask *mask); -void BKE_mask_free_nolib(struct Mask *mask); -void BKE_mask_free(struct Main *bmain, struct Mask *mask); +void BKE_mask_free(struct Mask *mask); void BKE_mask_coord_from_frame(float r_co[2], const float co[2], const float frame_size[2]); void BKE_mask_coord_from_movieclip(struct MovieClip *clip, struct MovieClipUser *user, float r_co[2], const float co[2]); diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index 0574b88bef3..b8258455c65 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -38,7 +38,6 @@ struct Object; struct Scene; struct MetaElem; -void BKE_mball_unlink(struct MetaBall *mb); void BKE_mball_free(struct MetaBall *mb); void BKE_mball_init(struct MetaBall *mb); struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index d8d869015a3..9330f41d19a 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -81,8 +81,7 @@ int poly_get_adj_loops_from_vert( int BKE_mesh_edge_other_vert(const struct MEdge *e, int v); -void BKE_mesh_unlink(struct Mesh *me); -void BKE_mesh_free(struct Mesh *me, int unlink); +void BKE_mesh_free(struct Mesh *me); void BKE_mesh_init(struct Mesh *me); struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name); struct Mesh *BKE_mesh_copy_ex(struct Main *bmain, struct Mesh *me); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 4b92c1f7a3a..bf198c9b86b 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -334,7 +334,6 @@ void ntreeInitDefault(struct bNodeTree *ntree); struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname); /* copy/free funcs, need to manage ID users */ -void ntreeFreeTree_ex(struct bNodeTree *ntree, const bool do_id_user); void ntreeFreeTree(struct bNodeTree *ntree); struct bNodeTree *ntreeCopyTree_ex(struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user); struct bNodeTree *ntreeCopyTree(struct bNodeTree *ntree); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index c591ec2a0aa..f46fb73f4c9 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -65,7 +65,6 @@ void BKE_object_free_curve_cache(struct Object *ob); void BKE_object_update_base_layer(struct Scene *scene, struct Object *ob); void BKE_object_free(struct Object *ob); -void BKE_object_free_ex(struct Object *ob, bool do_id_user); void BKE_object_free_derived_caches(struct Object *ob); void BKE_object_free_caches(struct Object *object); @@ -79,7 +78,6 @@ void BKE_object_free_modifiers(struct Object *ob); void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob); void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target); -void BKE_object_unlink(struct Main *bmain, struct Object *ob); bool BKE_object_exists_check(struct Object *obtest); bool BKE_object_is_in_editmode(struct Object *ob); bool BKE_object_is_in_editmode_vgroup(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h index fa448aa97b8..1743a4431fd 100644 --- a/source/blender/blenkernel/BKE_sca.h +++ b/source/blender/blenkernel/BKE_sca.h @@ -67,7 +67,6 @@ void clear_sca_new_poins_ob(struct Object *ob); void clear_sca_new_poins(void); void set_sca_new_poins_ob(struct Object *ob); void set_sca_new_poins(void); -void sca_remove_ob_poin(struct Object *obt, struct Object *ob); void sca_move_sensor(struct bSensor *sens_to_move, struct Object *ob, int move_up); void sca_move_controller(struct bController *cont_to_move, struct Object *ob, int move_up); diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 12bfc07e958..ccb7dc8e015 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -100,10 +100,11 @@ struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name); struct Scene *BKE_scene_copy(struct Scene *sce, int type); void BKE_scene_groups_relink(struct Scene *sce); -void BKE_scene_unlink(struct Main *bmain, struct Scene *sce, struct Scene *newsce); struct Object *BKE_scene_camera_find(struct Scene *sc); +#ifdef DURIAN_CAMERA_SWITCH struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH +#endif int BKE_scene_camera_switch_update(struct Scene *scene); char *BKE_scene_find_marker_name(struct Scene *scene, int frame); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index d05df3470b5..14e978b23f2 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -99,6 +99,9 @@ typedef struct SpaceType { /* return context data */ int (*context)(const struct bContext *, const char *, struct bContextDataResult *); + /* Used when we want to replace an ID by another (or NULL). */ + void (*id_remap)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *); + /* region type definitions */ ListBase regiontypes; @@ -274,8 +277,8 @@ void BKE_spacedata_freelist(ListBase *lb); void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2); void BKE_spacedata_draw_locks(int set); -void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *)); -void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id); +void BKE_spacedata_callback_id_remap_set(void (*func)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *)); +void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id); /* area/regions */ struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar); diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 67db2537c8f..18d9fe061a8 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -72,8 +72,6 @@ struct bSound *BKE_sound_new_buffer(struct Main *bmain, struct bSound *source); struct bSound *BKE_sound_new_limiter(struct Main *bmain, struct bSound *source, float start, float end); #endif -void BKE_sound_delete(struct Main *bmain, struct bSound *sound); - void BKE_sound_cache(struct bSound *sound); void BKE_sound_delete_cache(struct bSound *sound); diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h index 8d7ab230919..0be61fe0229 100644 --- a/source/blender/blenkernel/BKE_world.h +++ b/source/blender/blenkernel/BKE_world.h @@ -37,7 +37,6 @@ struct Main; struct World; void BKE_world_free(struct World *sc); -void BKE_world_free_ex(struct World *sc, bool do_id_user); void BKE_world_init(struct World *wrld); struct World *add_world(struct Main *bmian, const char *name); struct World *BKE_world_copy(struct World *wrld); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 86264224851..6af9f8a71ee 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -123,6 +123,7 @@ set(SRC intern/library.c intern/library_idmap.c intern/library_query.c + intern/library_remap.c intern/linestyle.c intern/mask.c intern/mask_evaluate.c @@ -247,6 +248,7 @@ set(SRC BKE_library.h BKE_library_idmap.h BKE_library_query.h + BKE_library_remap.h BKE_linestyle.h BKE_main.h BKE_mask.h diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index df9b9683687..46ee8a4d888 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -159,22 +159,19 @@ void BKE_action_make_local(bAction *act) /* .................................. */ +/** Free (or release) any data used by this action (does not free the action itself). */ void BKE_action_free(bAction *act) -{ - /* sanity check */ - if (act == NULL) - return; - +{ + /* No animdata here. */ + /* Free F-Curves */ free_fcurves(&act->curves); /* Free groups */ - if (act->groups.first) - BLI_freelistN(&act->groups); + BLI_freelistN(&act->groups); /* Free pose-references (aka local markers) */ - if (act->markers.first) - BLI_freelistN(&act->markers); + BLI_freelistN(&act->markers); } /* .................................. */ diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 99aae6239e8..91b33f3efd3 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -216,7 +216,7 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act) /* Freeing -------------------------------------------- */ /* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */ -void BKE_animdata_free(ID *id) +void BKE_animdata_free(ID *id, const bool do_id_user) { /* Only some ID-blocks have this info for now, so we cast the * types that do to be of type IdAdtTemplate @@ -227,12 +227,14 @@ void BKE_animdata_free(ID *id) /* check if there's any AnimData to start with */ if (adt) { - /* unlink action (don't free, as it's in its own list) */ - if (adt->action) - id_us_min(&adt->action->id); - /* same goes for the temporarily displaced action */ - if (adt->tmpact) - id_us_min(&adt->tmpact->id); + if (do_id_user) { + /* unlink action (don't free, as it's in its own list) */ + if (adt->action) + id_us_min(&adt->action->id); + /* same goes for the temporarily displaced action */ + if (adt->tmpact) + id_us_min(&adt->tmpact->id); + } /* free nla data */ free_nladata(&adt->nla_tracks); @@ -292,7 +294,7 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action) if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) return false; - BKE_animdata_free(id_to); + BKE_animdata_free(id_to, true); adt = BKE_animdata_from_id(id_from); if (adt) { diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 04b4733fd44..038993777cf 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -120,30 +120,25 @@ void BKE_armature_bonelist_free(ListBase *lb) BLI_freelistN(lb); } +/** Free (or release) any data used by this armature (does not free the armature itself). */ void BKE_armature_free(bArmature *arm) { - if (arm) { - BKE_armature_bonelist_free(&arm->bonebase); + BKE_animdata_free(&arm->id, false); - /* free editmode data */ - if (arm->edbo) { - BLI_freelistN(arm->edbo); + BKE_armature_bonelist_free(&arm->bonebase); - MEM_freeN(arm->edbo); - arm->edbo = NULL; - } + /* free editmode data */ + if (arm->edbo) { + BLI_freelistN(arm->edbo); - /* free sketch */ - if (arm->sketch) { - freeSketch(arm->sketch); - arm->sketch = NULL; - } + MEM_freeN(arm->edbo); + arm->edbo = NULL; + } - /* free animation data */ - if (arm->adt) { - BKE_animdata_free(&arm->id); - arm->adt = NULL; - } + /* free sketch */ + if (arm->sketch) { + freeSketch(arm->sketch); + arm->sketch = NULL; } } diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index da7863096e3..a3e006a162f 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -202,22 +202,18 @@ Brush *BKE_brush_copy(Brush *brush) return brushn; } -/* not brush itself */ +/** Free (or release) any data used by this brush (does not free the brush itself). */ void BKE_brush_free(Brush *brush) { - id_us_min((ID *)brush->mtex.tex); - id_us_min((ID *)brush->mask_mtex.tex); - id_us_min((ID *)brush->paint_curve); - - if (brush->icon_imbuf) + if (brush->icon_imbuf) { IMB_freeImBuf(brush->icon_imbuf); - - BKE_previewimg_free(&(brush->preview)); + } curvemapping_free(brush->curve); - if (brush->gradient) - MEM_freeN(brush->gradient); + MEM_SAFE_FREE(brush->gradient); + + BKE_previewimg_free(&(brush->preview)); } /** diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 96bac2c2f41..eabee742327 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -153,9 +153,10 @@ void BKE_camera_make_local(Camera *cam) } } +/** Free (or release) any data used by this camera (does not free the camera itself). */ void BKE_camera_free(Camera *ca) { - BKE_animdata_free((ID *)ca); + BKE_animdata_free((ID *)ca, false); } /******************************** Camera Usage *******************************/ diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 8afb451f768..dec6ff22360 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -69,36 +69,6 @@ static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], c short cox, short coy, float *lambda, float *mu, float vec[3]); -void BKE_curve_unlink(Curve *cu) -{ - int a; - - for (a = 0; a < cu->totcol; a++) { - if (cu->mat[a]) - id_us_min(&cu->mat[a]->id); - cu->mat[a] = NULL; - } - if (cu->vfont) - id_us_min(&cu->vfont->id); - cu->vfont = NULL; - - if (cu->vfontb) - id_us_min(&cu->vfontb->id); - cu->vfontb = NULL; - - if (cu->vfonti) - id_us_min(&cu->vfonti->id); - cu->vfonti = NULL; - - if (cu->vfontbi) - id_us_min(&cu->vfontbi->id); - cu->vfontbi = NULL; - - if (cu->key) - id_us_min(&cu->key->id); - cu->key = NULL; -} - /* frees editcurve entirely */ void BKE_curve_editfont_free(Curve *cu) { @@ -136,26 +106,21 @@ void BKE_curve_editNurb_free(Curve *cu) } } -/* don't free curve itself */ +/** Free (or release) any data used by this curve (does not free the curve itself). */ void BKE_curve_free(Curve *cu) { + BKE_animdata_free((ID *)cu, false); + BKE_nurbList_free(&cu->nurb); BKE_curve_editfont_free(cu); BKE_curve_editNurb_free(cu); - BKE_curve_unlink(cu); - BKE_animdata_free((ID *)cu); - - if (cu->mat) - MEM_freeN(cu->mat); - if (cu->str) - MEM_freeN(cu->str); - if (cu->strinfo) - MEM_freeN(cu->strinfo); - if (cu->bb) - MEM_freeN(cu->bb); - if (cu->tb) - MEM_freeN(cu->tb); + + MEM_SAFE_FREE(cu->mat); + MEM_SAFE_FREE(cu->str); + MEM_SAFE_FREE(cu->strinfo); + MEM_SAFE_FREE(cu->bb); + MEM_SAFE_FREE(cu->tb); } void BKE_curve_init(Curve *cu) diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index f06dd6f9de4..a8268c03d95 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -139,9 +139,6 @@ void free_partdeflect(PartDeflect *pd) if (!pd) return; - if (pd->tex) - id_us_min(&pd->tex->id); - if (pd->rng) BLI_rng_free(pd->rng); diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 812d1c66923..5e1f8814ed6 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -95,10 +95,9 @@ void BKE_vfont_free_data(struct VFont *vfont) } } +/** Free (or release) any data used by this font (does not free the font itself). */ void BKE_vfont_free(struct VFont *vf) { - if (vf == NULL) return; - BKE_vfont_free_data(vf); if (vf->packedfile) { diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index f3eb5430bce..af1bcd0c545 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -113,16 +113,13 @@ void free_gpencil_layers(ListBase *list) } /* Free all of GPencil datablock's related data, but not the block itself */ +/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */ void BKE_gpencil_free(bGPdata *gpd) { + BKE_animdata_free(&gpd->id, false); + /* free layers */ free_gpencil_layers(&gpd->layers); - - /* free animation data */ - if (gpd->adt) { - BKE_animdata_free(&gpd->id); - gpd->adt = NULL; - } } /* -------- Container Creation ---------- */ diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index a44eb1df9fe..4fdee7e3633 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -60,79 +60,19 @@ static void free_group_object(GroupObject *go) MEM_freeN(go); } - +/** Free (or release) any data used by this group (does not free the group itself). */ void BKE_group_free(Group *group) { /* don't free group itself */ GroupObject *go; - BKE_previewimg_free(&group->preview); + /* No animdata here. */ while ((go = BLI_pophead(&group->gobject))) { free_group_object(go); } -} -void BKE_group_unlink(Main *bmain, Group *group) -{ - Material *ma; - Object *ob; - Scene *sce; - SceneRenderLayer *srl; - ParticleSystem *psys; - - for (ma = bmain->mat.first; ma; ma = ma->id.next) { - if (ma->group == group) - ma->group = NULL; - } - for (ma = bmain->mat.first; ma; ma = ma->id.next) { - if (ma->group == group) - ma->group = NULL; - } - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - Base *base = sce->base.first; - - /* ensure objects are not in this group */ - for (; base; base = base->next) { - if (BKE_group_object_unlink(group, base->object, sce, base) && - BKE_group_object_find(NULL, base->object) == NULL) - { - base->object->flag &= ~OB_FROMGROUP; - base->flag &= ~OB_FROMGROUP; - } - } - - for (srl = sce->r.layers.first; srl; srl = srl->next) { - FreestyleLineSet *lineset; - - if (srl->light_override == group) - srl->light_override = NULL; - for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { - if (lineset->group == group) - lineset->group = NULL; - } - } - } - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - - if (ob->dup_group == group) { - ob->dup_group = NULL; - } - - for (psys = ob->particlesystem.first; psys; psys = psys->next) { - if (psys->part->dup_group == group) - psys->part->dup_group = NULL; -#if 0 /* not used anymore, only keps for readfile.c, no need to account for this */ - if (psys->part->eff_group == group) - psys->part->eff_group = NULL; -#endif - } - } - - /* group stays in library, but no members */ - BKE_group_free(group); - group->id.us = 0; + BKE_previewimg_free(&group->preview); } Group *BKE_group_add(Main *bmain, const char *name) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 0b2c844cb2c..14a445649ad 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -324,20 +324,16 @@ void BKE_image_free_buffers(Image *ima) ima->ok = IMA_OK; } -/* called by library too, do not free ima itself */ +/** Free (or release) any data used by this image (does not free the image itself). */ void BKE_image_free(Image *ima) { int a; + /* Also frees animdata. */ BKE_image_free_buffers(ima); image_free_packedfiles(ima); - BKE_icon_id_delete(&ima->id); - ima->id.icon_id = 0; - - BKE_previewimg_free(&ima->preview); - for (a = 0; a < IMA_MAX_RENDER_SLOT; a++) { if (ima->renders[a]) { RE_FreeRenderResult(ima->renders[a]); @@ -346,7 +342,10 @@ void BKE_image_free(Image *ima) } BKE_image_free_views(ima); - MEM_freeN(ima->stereo3d_format); + MEM_SAFE_FREE(ima->stereo3d_format); + + BKE_icon_id_delete(&ima->id); + BKE_previewimg_free(&ima->preview); } /* only image block itself */ diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 362f41335d2..2517e2cc197 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -74,11 +74,13 @@ #define IPO_BEZTRIPLE 100 #define IPO_BPOINT 101 + +/** Free (or release) any data used by this shapekey (does not free the key itself). */ void BKE_key_free(Key *key) { KeyBlock *kb; - - BKE_animdata_free((ID *)key); + + BKE_animdata_free((ID *)key, false); while ((kb = BLI_pophead(&key->block))) { if (kb->data) diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 49a573489ef..692b703f721 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -234,7 +234,7 @@ void BKE_lamp_free(Lamp *la) MEM_freeN(mtex); } - BKE_animdata_free((ID *)la); + BKE_animdata_free((ID *)la, false); curvemapping_free(la->curfalloff); diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index b350e932281..58c0a567116 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -300,24 +300,27 @@ Lattice *BKE_lattice_copy(Lattice *lt) return ltn; } +/** Free (or release) any data used by this lattice (does not free the lattice itself). */ void BKE_lattice_free(Lattice *lt) { - if (lt->def) MEM_freeN(lt->def); - if (lt->dvert) BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + BKE_animdata_free(<->id, false); + + MEM_SAFE_FREE(lt->def); + if (lt->dvert) { + BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + lt->dvert = NULL; + } if (lt->editlatt) { Lattice *editlt = lt->editlatt->latt; - if (editlt->def) MEM_freeN(editlt->def); - if (editlt->dvert) BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + if (editlt->def) + MEM_freeN(editlt->def); + if (editlt->dvert) + BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); MEM_freeN(editlt); MEM_freeN(lt->editlatt); - } - - /* free animation data */ - if (lt->adt) { - BKE_animdata_free(<->id); - lt->adt = NULL; + lt->editlatt = NULL; } } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 961b45df4e6..fe16df18813 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -84,7 +84,6 @@ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" -#include "BKE_fcurve.h" #include "BKE_font.h" #include "BKE_global.h" #include "BKE_group.h" @@ -92,7 +91,6 @@ #include "BKE_idcode.h" #include "BKE_idprop.h" #include "BKE_image.h" -#include "BKE_ipo.h" #include "BKE_key.h" #include "BKE_lamp.h" #include "BKE_lattice.h" @@ -103,16 +101,12 @@ #include "BKE_material.h" #include "BKE_main.h" #include "BKE_mball.h" -#include "BKE_movieclip.h" #include "BKE_mask.h" #include "BKE_node.h" #include "BKE_object.h" -#include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_packedFile.h" #include "BKE_speaker.h" -#include "BKE_sound.h" -#include "BKE_screen.h" #include "BKE_scene.h" #include "BKE_text.h" #include "BKE_texture.h" @@ -125,10 +119,6 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#ifdef WITH_PYTHON -#include "BPY_extern.h" -#endif - /* GS reads the memory pointed at in a specific ordering. * only use this definition, makes little and big endian systems * work fine, in conjunction with MAKE_ID */ @@ -182,7 +172,6 @@ void id_us_ensure_real(ID *id) } } -/* Unused currently... */ void id_us_clear_real(ID *id) { if (id && (id->tag & LIB_TAG_EXTRAUSER)) { @@ -232,9 +221,7 @@ void id_us_min(ID *id) if (id->us <= limit) { printf("ID user decrement error: %s (from '%s'): %d <= %d\n", id->name, id->lib ? id->lib->filepath : "[Main]", id->us, limit); - /* We cannot assert here, because of how we 'delete' datablocks currently (setting their usercount to zero), - * this is weak but it's how it works for now. */ - /* BLI_assert(0); */ + BLI_assert(0); id->us = limit; } else { @@ -462,37 +449,6 @@ bool id_copy(ID *id, ID **newid, bool test) return false; } -bool id_unlink(ID *id, int test) -{ - Main *mainlib = G.main; - short type = GS(id->name); - - switch (type) { - case ID_TXT: - if (test) return true; - BKE_text_unlink(mainlib, (Text *)id); - break; - case ID_GR: - if (test) return true; - BKE_group_unlink(mainlib, (Group *)id); - break; - case ID_OB: - if (test) return true; - BKE_object_unlink(mainlib, (Object *)id); - break; - } - - if (id->us == 0) { - if (test) return true; - - BKE_libblock_free(mainlib, id); - - return true; - } - - return false; -} - bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) { ID *newid = NULL; @@ -1111,234 +1067,12 @@ void BKE_libblock_relink(ID *id) BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0); } -static void BKE_library_free(Library *lib) +void BKE_library_free(Library *lib) { if (lib->packedfile) freePackedFile(lib->packedfile); } -static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL; - -void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func) -{ - free_windowmanager_cb = func; -} - -static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL; - -void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func) -{ - free_notifier_reference_cb = func; -} - -static BKE_library_free_editor_id_reference_cb free_editor_id_reference_cb = NULL; - -void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func) -{ - free_editor_id_reference_cb = func; -} - -static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata) -{ - ChannelDriver *driver; - FCurve *fcu; - - /* find the driver this belongs to and update it */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - driver = fcu->driver; - - if (driver) { - DriverVar *dvar; - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - DRIVER_TARGETS_USED_LOOPER(dvar) - { - if (dtar->id == userdata) - dtar->id = NULL; - } - DRIVER_TARGETS_LOOPER_END - } - } - } -} - -void BKE_libblock_free_data(Main *bmain, ID *id) -{ - if (id->properties) { - IDP_FreeProperty(id->properties); - MEM_freeN(id->properties); - } - - /* this ID may be a driver target! */ - BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id); -} - -/* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c */ -void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user) -{ - ID *id = idv; - short type = GS(id->name); - ListBase *lb = which_libbase(bmain, type); - - DAG_id_type_tag(bmain, type); - -#ifdef WITH_PYTHON - BPY_id_release(id); -#endif - - switch (type) { /* GetShort from util.h */ - case ID_SCE: - BKE_scene_free((Scene *)id); - break; - case ID_LI: - BKE_library_free((Library *)id); - break; - case ID_OB: - BKE_object_free_ex((Object *)id, do_id_user); - break; - case ID_ME: - BKE_mesh_free((Mesh *)id, 1); - break; - case ID_CU: - BKE_curve_free((Curve *)id); - break; - case ID_MB: - BKE_mball_free((MetaBall *)id); - break; - case ID_MA: - BKE_material_free((Material *)id); - break; - case ID_TE: - BKE_texture_free((Tex *)id); - break; - case ID_IM: - BKE_image_free((Image *)id); - break; - case ID_LT: - BKE_lattice_free((Lattice *)id); - break; - case ID_LA: - BKE_lamp_free((Lamp *)id); - break; - case ID_CA: - BKE_camera_free((Camera *) id); - break; - case ID_IP: - BKE_ipo_free((Ipo *)id); - break; - case ID_KE: - BKE_key_free((Key *)id); - break; - case ID_WO: - BKE_world_free((World *)id); - break; - case ID_SCR: - BKE_screen_free((bScreen *)id); - break; - case ID_VF: - BKE_vfont_free((VFont *)id); - break; - case ID_TXT: - BKE_text_free((Text *)id); - break; - case ID_SPK: - BKE_speaker_free((Speaker *)id); - break; - case ID_SO: - BKE_sound_free((bSound *)id); - break; - case ID_GR: - BKE_group_free((Group *)id); - break; - case ID_AR: - BKE_armature_free((bArmature *)id); - break; - case ID_AC: - BKE_action_free((bAction *)id); - break; - case ID_NT: - ntreeFreeTree_ex((bNodeTree *)id, do_id_user); - break; - case ID_BR: - BKE_brush_free((Brush *)id); - break; - case ID_PA: - BKE_particlesettings_free((ParticleSettings *)id); - break; - case ID_WM: - if (free_windowmanager_cb) - free_windowmanager_cb(NULL, (wmWindowManager *)id); - break; - case ID_GD: - BKE_gpencil_free((bGPdata *)id); - break; - case ID_MC: - BKE_movieclip_free((MovieClip *)id); - break; - case ID_MSK: - BKE_mask_free(bmain, (Mask *)id); - break; - case ID_LS: - BKE_linestyle_free((FreestyleLineStyle *)id); - break; - case ID_PAL: - BKE_palette_free((Palette *)id); - break; - case ID_PC: - BKE_paint_curve_free((PaintCurve *)id); - break; - } - - /* avoid notifying on removed data */ - BKE_main_lock(bmain); - - if (free_notifier_reference_cb) { - free_notifier_reference_cb(id); - } - - if (free_editor_id_reference_cb) { - free_editor_id_reference_cb(id); - } - - BLI_remlink(lb, id); - - BKE_libblock_free_data(bmain, id); - BKE_main_unlock(bmain); - - MEM_freeN(id); -} - -void BKE_libblock_free(Main *bmain, void *idv) -{ - BKE_libblock_free_ex(bmain, idv, true); -} - -void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ -{ - ID *id = idv; - - id_us_min(id); - - /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object. - * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes, - * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets - * fully unlinked. - * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO. - */ - if ((GS(id->name) == ID_OB) && (id->us == 1)) { - id_us_clear_real(id); - } - - if (id->us == 0) { - switch (GS(id->name)) { - case ID_OB: - BKE_object_unlink(bmain, (Object *)id); - break; - } - - BKE_libblock_free(bmain, id); - } -} - Main *BKE_main_new(void) { Main *bmain = MEM_callocN(sizeof(Main), "new main"); diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 4fe408e755a..be3dde2753a 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -29,6 +29,7 @@ #include <stdlib.h> +#include "MEM_guardedalloc.h" #include "DNA_actuator_types.h" #include "DNA_anim_types.h" @@ -61,6 +62,7 @@ #include "DNA_world_types.h" #include "BLI_utildefines.h" +#include "BLI_listbase.h" #include "BLI_ghash.h" #include "BLI_linklist_stack.h" @@ -69,6 +71,7 @@ #include "BKE_fcurve.h" #include "BKE_library.h" #include "BKE_library_query.h" +#include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_rigidbody.h" @@ -198,9 +201,24 @@ static void library_foreach_actuatorsObjectLooper( FOREACH_FINALIZE_VOID; } +static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip) +{ + NlaStrip *substrip; + + FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_USER); + + for (substrip = strip->strips.first; substrip; substrip = substrip->next) { + library_foreach_nla_strip(data, substrip); + } + + FOREACH_FINALIZE_VOID; +} + static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt) { FCurve *fcu; + NlaTrack *nla_track; + NlaStrip *nla_strip; for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { ChannelDriver *driver = fcu->driver; @@ -216,6 +234,15 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData * } } + FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_USER); + FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_USER); + + for (nla_track = adt->nla_tracks.first; nla_track; nla_track = nla_track->next) { + for (nla_strip = nla_track->strips.first; nla_strip; nla_strip = nla_strip->next) { + library_foreach_nla_strip(data, nla_strip); + } + } + FOREACH_FINALIZE_VOID; } @@ -276,6 +303,12 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } switch (GS(id->name)) { + case ID_LI: + { + Library *lib = (Library *) id; + CALLBACK_INVOKE(lib->parent, IDWALK_NOP); + break; + } case ID_SCE: { Scene *scene = (Scene *) id; @@ -287,7 +320,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(scene->world, IDWALK_USER); CALLBACK_INVOKE(scene->set, IDWALK_NOP); CALLBACK_INVOKE(scene->clip, IDWALK_USER); - CALLBACK_INVOKE(scene->nodetree, IDWALK_NOP); + if (scene->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)scene->nodetree, callback, user_data, flag); + } /* DO NOT handle scene->basact here, it's doubling with the loop over whole scene->base later, * since basact is just a pointer to one of those items. */ CALLBACK_INVOKE(scene->obedit, IDWALK_NOP); @@ -438,6 +474,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data); } + if (object->soft && object->soft->effector_weights) { + CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP); + } + BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data); BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data); BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data); @@ -489,7 +529,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u library_foreach_mtex(&data, material->mtex[i]); } } - CALLBACK_INVOKE(material->nodetree, IDWALK_NOP); + if (material->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)material->nodetree, callback, user_data, flag); + } CALLBACK_INVOKE(material->group, IDWALK_USER); break; } @@ -497,7 +540,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_TE: { Tex *texture = (Tex *) id; - CALLBACK_INVOKE(texture->nodetree, IDWALK_NOP); + if (texture->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)texture->nodetree, callback, user_data, flag); + } CALLBACK_INVOKE(texture->ima, IDWALK_USER); if (texture->env) { CALLBACK_INVOKE(texture->env->object, IDWALK_NOP); @@ -527,7 +573,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u library_foreach_mtex(&data, lamp->mtex[i]); } } - CALLBACK_INVOKE(lamp->nodetree, IDWALK_NOP); + if (lamp->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)lamp->nodetree, callback, user_data, flag); + } break; } @@ -560,7 +609,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u library_foreach_mtex(&data, world->mtex[i]); } } - CALLBACK_INVOKE(world->nodetree, IDWALK_NOP); + if (world->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)world->nodetree, callback, user_data, flag); + } break; } @@ -700,7 +752,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u library_foreach_mtex(&data, linestyle->mtex[i]); } } - CALLBACK_INVOKE(linestyle->nodetree, IDWALK_NOP); + if (linestyle->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)linestyle->nodetree, callback, user_data, flag); + } for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) { if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { @@ -769,11 +824,18 @@ typedef struct IDUsersIter { int count; /* Set by callback. */ } IDUsersIter; -static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int UNUSED(cb_flag)) +static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int cb_flag) { IDUsersIter *iter = user_data; if (*id_p && (*id_p == iter->id)) { +#if 0 + printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d)\n", + iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0, + (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0); +#else + UNUSED_VARS(cb_flag); +#endif iter->count++; } diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c new file mode 100644 index 00000000000..4bde0752ef3 --- /dev/null +++ b/source/blender/blenkernel/intern/library_remap.c @@ -0,0 +1,768 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/library_remap.c + * \ingroup bke + * + * Contains management of ID's and libraries remap, unlink and free logic. + */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> +#include <assert.h> + +#include "MEM_guardedalloc.h" + +/* all types are needed here, in order to do memory operations */ +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_brush_types.h" +#include "DNA_camera_types.h" +#include "DNA_group_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_ipo_types.h" +#include "DNA_key_types.h" +#include "DNA_lamp_types.h" +#include "DNA_lattice_types.h" +#include "DNA_linestyle_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meta_types.h" +#include "DNA_movieclip_types.h" +#include "DNA_mask_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_speaker_types.h" +#include "DNA_sound_types.h" +#include "DNA_text_types.h" +#include "DNA_vfont_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_world_types.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "BKE_action.h" +#include "BKE_animsys.h" +#include "BKE_armature.h" +#include "BKE_brush.h" +#include "BKE_camera.h" +#include "BKE_curve.h" +#include "BKE_depsgraph.h" +#include "BKE_fcurve.h" +#include "BKE_font.h" +#include "BKE_group.h" +#include "BKE_gpencil.h" +#include "BKE_idprop.h" +#include "BKE_image.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_lamp.h" +#include "BKE_lattice.h" +#include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" +#include "BKE_linestyle.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_main.h" +#include "BKE_mball.h" +#include "BKE_movieclip.h" +#include "BKE_mask.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_particle.h" +#include "BKE_speaker.h" +#include "BKE_sound.h" +#include "BKE_screen.h" +#include "BKE_scene.h" +#include "BKE_text.h" +#include "BKE_texture.h" +#include "BKE_world.h" + +#ifdef WITH_PYTHON +#include "BPY_extern.h" +#endif + +static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL; + +void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func) +{ + free_windowmanager_cb = func; +} + +static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL; + +void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func) +{ + free_notifier_reference_cb = func; +} + +static BKE_library_remap_editor_id_reference_cb remap_editor_id_reference_cb = NULL; + +void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func) +{ + remap_editor_id_reference_cb = func; +} + +typedef struct IDRemap { + ID *old_id; + ID *new_id; + ID *id; /* The ID in which we are replacing old_id by new_id usages. */ + short flag; + + /* 'Output' data. */ + short status; + int skipped_direct; /* Number of direct usecases that could not be remapped (e.g.: obdata when in edit mode). */ + int skipped_indirect; /* Number of indirect usecases that could not be remapped. */ + int skipped_refcounted; /* Number of skipped usecases that refcount the datablock. */ +} IDRemap; + +/* IDRemap->flag enums defined in BKE_library.h */ + +/* IDRemap->status */ +enum { + /* *** Set by callback. *** */ + ID_REMAP_IS_LINKED_DIRECT = 1 << 0, /* new_id is directly linked in current .blend. */ + ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* There was some skipped 'user_one' usages of old_id. */ +}; + +static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), ID **id_p, int cb_flag) +{ + IDRemap *id_remap_data = user_data; + ID *old_id = id_remap_data->old_id; + ID *new_id = id_remap_data->new_id; + ID *id = id_remap_data->id; + + if (!old_id) { /* Used to cleanup all IDs used by a specific one. */ + BLI_assert(!new_id); + old_id = *id_p; + } + + if (*id_p && (*id_p == old_id)) { + /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct, + * on the other hand since they get reset to lib data on file open/reload it is indirect too... + * Edit Mode is also a 'skip direct' case. */ + const bool is_obj = (GS(id->name) == ID_OB); + const bool is_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group)); + const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id)); + /* Note that indirect data from same file as processed ID is **not** considered indirect! */ + const bool is_indirect = ((id->lib != NULL) && (id->lib != old_id->lib)); + const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; + const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) && + (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); + const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0; + + if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_NEVER_NULL)) { + id->tag |= LIB_TAG_DOIT; + } + + /* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */ + if ((is_never_null && skip_never_null) || + (is_obj_editmode && (((Object *)id)->data == *id_p)) || + (skip_indirect && (is_proxy || is_indirect))) + { + if (is_never_null || is_proxy || is_obj_editmode) { + id_remap_data->skipped_direct++; + } + else { + id_remap_data->skipped_indirect++; + } + if (cb_flag & IDWALK_USER) { + id_remap_data->skipped_refcounted++; + } + else if (cb_flag & IDWALK_USER_ONE) { + /* No need to count number of times this happens, just a flag is enough. */ + id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED; + } + } + else { + if (!is_never_null) { + *id_p = new_id; + } + if (cb_flag & IDWALK_USER) { + id_us_min(old_id); + /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */ + if (new_id) + new_id->us++; + } + else if (cb_flag & IDWALK_USER_ONE) { + id_us_ensure_real(new_id); + /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed, + * that extra user is processed in final handling... */ + } + if (!is_indirect) { + id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; + } + } + } + + return IDWALK_RET_NOP; +} + +/** + * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks). + * + * Behavior differs depending on whether given \a id is NULL or not: + * - \a id NULL: \a old_id must be non-NULL, \a new_id may be NULL (unlinking \a old_id) or not + * (remapping \a old_id to \a new_id). The whole \a bmain database is checked, and all pointers to \a old_id + * are remapped to \a new_id. + * - \a id is non-NULL: + * + If \a old_id is NULL, \a new_id must also be NULL, and all ID pointers from \a id are cleared (i.e. \a id + * does not references any other datablock anymore). + * + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only for given \a id. + * + * \param bmain: the Main data storage to operate on (can be NULL if \a id is non-NULL). + * \param id: the datablock to operate on (can be NULL if \a bmain is non-NULL). + * \param old_id: the datablock to dereference (may be NULL if \a id is non-NULL). + * \param new_id: the new datablock to replace \a old_id references with (may be NULL). + * \param r_id_remap_data: if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process). + */ +static void libblock_remap_data( + Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data) +{ + IDRemap id_remap_data; + ListBase *lb_array[MAX_LIBARRAY]; + int i; + + if (r_id_remap_data == NULL) { + r_id_remap_data = &id_remap_data; + } + r_id_remap_data->old_id = old_id; + r_id_remap_data->new_id = new_id; + r_id_remap_data->id = NULL; + r_id_remap_data->flag = remap_flags; + r_id_remap_data->status = 0; + r_id_remap_data->skipped_direct = 0; + r_id_remap_data->skipped_indirect = 0; + r_id_remap_data->skipped_refcounted = 0; + + if (id) { +#ifdef DEBUG_PRINT + printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib); +#endif + r_id_remap_data->id = id; + BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP); + } + else { + i = set_listbasepointers(bmain, lb_array); + + /* Note that this is a very 'bruteforce' approach, maybe we could use some depsgraph to only process + * objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */ + + while (i--) { + ID *id_curr = lb_array[i]->first; + + for (; id_curr; id_curr = id_curr->next) { + /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for + * the user count handling... + * XXX No more true (except for debug usage of those skipping counters). */ + r_id_remap_data->id = id_curr; + BKE_library_foreach_ID_link( + id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP); + } + } + } + + /* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior + * though, we can always add an option (flag) to control this later if needed. */ + if (old_id && (old_id->flag & LIB_FAKEUSER)) { + id_fake_user_clear(old_id); + id_fake_user_set(new_id); + } + + id_us_clear_real(old_id); + + if (new_id && (new_id->tag & LIB_TAG_INDIRECT) && (r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) { + new_id->tag &= ~LIB_TAG_INDIRECT; + new_id->tag |= LIB_TAG_EXTERN; + } + +#ifdef DEBUG_PRINT + printf("%s: %d occurences skipped (%d direct and %d indirect ones)\n", __func__, + r_id_remap_data->skipped_direct + r_id_remap_data->skipped_indirect, + r_id_remap_data->skipped_direct, r_id_remap_data->skipped_indirect); +#endif +} + +/** + * Replace all references in given Main to \a old_id by \a new_id + * (if \a new_id is NULL, it unlinks \a old_id). + */ +void BKE_libblock_remap_locked( + Main *bmain, void *old_idv, void *new_idv, + const short remap_flags) +{ + IDRemap id_remap_data; + ID *old_id = old_idv; + ID *new_id = new_idv; + int skipped_direct, skipped_refcounted; + + BLI_assert(old_id != NULL); + BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name)); + BLI_assert(old_id != new_id); + + /* Some pre-process updates. + * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead? + */ + if (GS(old_id->name) == ID_OB) { + Object *old_ob = (Object *)old_id; + Object *new_ob = (Object *)new_id; + + if (new_ob == NULL) { + Scene *sce; + Base *base; + + for (sce = bmain->scene.first; sce; sce = sce->id.next) { + base = BKE_scene_base_find(sce, old_ob); + + if (base) { + id_us_min((ID *)base->object); + BKE_scene_base_unlink(sce, base); + MEM_freeN(base); + } + } + } + } + + libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data); + + if (free_notifier_reference_cb) { + free_notifier_reference_cb(old_id); + } + + /* We assume editors do not hold references to their IDs... This is false in some cases + * (Image is especially tricky here), editors' code is to handle refcount (id->us) itself then. */ + if (remap_editor_id_reference_cb) { + remap_editor_id_reference_cb(old_id, new_id); + } + + skipped_direct = id_remap_data.skipped_direct; + skipped_refcounted = id_remap_data.skipped_refcounted; + + /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user count has actually + * been incremented for that, we have to decrease once more its user count... unless we had to skip + * some 'user_one' cases. */ + if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) { + id_us_min(old_id); + old_id->tag &= ~LIB_TAG_EXTRAUSER_SET; + } + + BLI_assert(old_id->us - skipped_refcounted >= 0); + UNUSED_VARS_NDEBUG(skipped_refcounted); + + if (skipped_direct == 0) { + /* old_id is assumed to not be used directly anymore... */ + if (old_id->lib && (old_id->tag & LIB_TAG_EXTERN)) { + old_id->tag &= ~LIB_TAG_EXTERN; + old_id->tag |= LIB_TAG_INDIRECT; + } + } + + /* Some after-process updates. + * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead? + */ + switch (GS(old_id->name)) { + case ID_OB: + { + Object *old_ob = (Object *)old_id; + Object *new_ob = (Object *)new_id; + + if (old_ob->flag & OB_FROMGROUP) { + /* Note that for Scene's BaseObject->flag, either we: + * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already. + * - remaped old_ob by new_ob, in which case scenes' bases are still valid as is. + * So in any case, no need to update them here. */ + if (BKE_group_object_find(NULL, old_ob) == NULL) { + old_ob->flag &= ~OB_FROMGROUP; + } + if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */ + Group *group; + for (group = bmain->group.first; group; group = group->id.next) { + BKE_group_object_unlink(group, NULL, NULL, NULL); + } + } + else { + new_ob->flag |= OB_FROMGROUP; + } + } + break; + } + case ID_GR: + if (new_id == NULL) { /* Only affects us in case group was unlinked. */ + for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { + /* Note that here we assume no object has no base (i.e. all objects are assumed instanced + * in one scene...). */ + for (Base *base = sce->base.first; base; base = base->next) { + if (base->flag & OB_FROMGROUP) { + Object *ob = base->object; + + if (ob->flag & OB_FROMGROUP) { + Group *grp = BKE_group_object_find(NULL, ob); + + /* Unlinked group (old_id) is still in bmain... */ + if (grp && (&grp->id == old_id)) { + grp = BKE_group_object_find(grp, ob); + } + if (!grp) { + ob->flag &= ~OB_FROMGROUP; + } + } + if (!(ob->flag & OB_FROMGROUP)) { + base->flag &= ~OB_FROMGROUP; + } + } + } + } + } + break; + default: + break; + } + + /* Full rebuild of DAG! */ + DAG_relations_tag_update(bmain); +} + +void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags) +{ + BKE_main_lock(bmain); + + BKE_libblock_remap_locked(bmain, old_idv, new_idv, remap_flags); + + BKE_main_unlock(bmain); +} + +/** + * Unlink given \a id from given \a bmain (does not touch to indirect, i.e. library, usages of the ID). + * + * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by \a LIB_TAG_DOIT flag + * (quite obviously, 'non-NULL' usages can never be unlinked by this function...). + */ +void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null) +{ + const short remap_flags = ID_REMAP_SKIP_INDIRECT_USAGE | (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0); + + BKE_main_lock(bmain); + + BKE_libblock_remap_locked(bmain, idv, NULL, remap_flags); + + BKE_main_unlock(bmain); +} + +/** Similar to libblock_remap, but only affects IDs used by given \a idv ID. + * + * \param old_idv: Unlike BKE_libblock_remap, can be NULL, + * in which case all ID usages by given \a idv will be cleared. + * \param us_min_never_null: If \a true and new_id is NULL, + * 'NEVER_NULL' ID usages keep their old id, but this one still gets its user count decremented + * (needed when given \a idv is going to be deleted right after being unlinked). + */ +/* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */ +/* XXX Arg! Naming... :( + * _relink? avoids confusion with _remap, but is confusing with _unlink + * _remap_used_ids? + * _remap_datablocks? + * BKE_id_remap maybe? + * ... sigh + */ +void BKE_libblock_relink_ex( + void *idv, void *old_idv, void *new_idv, const bool us_min_never_null) +{ + ID *id = idv; + ID *old_id = old_idv; + ID *new_id = new_idv; + int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE; + + /* No need to lock here, we are only affecting given ID. */ + + BLI_assert(id); + if (old_id) { + BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name)); + BLI_assert(old_id != new_id); + } + else { + BLI_assert(new_id == NULL); + } + + libblock_remap_data(NULL, id, old_id, new_id, remap_flags, NULL); +} + +static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata) +{ + ChannelDriver *driver; + FCurve *fcu; + + /* find the driver this belongs to and update it */ + for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + driver = fcu->driver; + + if (driver) { + DriverVar *dvar; + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + DRIVER_TARGETS_USED_LOOPER(dvar) + { + if (dtar->id == userdata) + dtar->id = NULL; + } + DRIVER_TARGETS_LOOPER_END + } + } + } +} + +void BKE_libblock_free_data(Main *bmain, ID *id) +{ + if (id->properties) { + IDP_FreeProperty(id->properties); + MEM_freeN(id->properties); + } + + /* this ID may be a driver target! */ + BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id); +} + +/** + * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c + * + * \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv. + */ +void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user) +{ + ID *id = idv; + short type = GS(id->name); + ListBase *lb = which_libbase(bmain, type); + + DAG_id_type_tag(bmain, type); + +#ifdef WITH_PYTHON + BPY_id_release(id); +#endif + + if (do_id_user) { + BKE_libblock_relink_ex(id, NULL, NULL, true); + } + + switch (type) { + case ID_SCE: + BKE_scene_free((Scene *)id); + break; + case ID_LI: + BKE_library_free((Library *)id); + break; + case ID_OB: + BKE_object_free((Object *)id); + break; + case ID_ME: + BKE_mesh_free((Mesh *)id); + break; + case ID_CU: + BKE_curve_free((Curve *)id); + break; + case ID_MB: + BKE_mball_free((MetaBall *)id); + break; + case ID_MA: + BKE_material_free((Material *)id); + break; + case ID_TE: + BKE_texture_free((Tex *)id); + break; + case ID_IM: + BKE_image_free((Image *)id); + break; + case ID_LT: + BKE_lattice_free((Lattice *)id); + break; + case ID_LA: + BKE_lamp_free((Lamp *)id); + break; + case ID_CA: + BKE_camera_free((Camera *) id); + break; + case ID_IP: /* Deprecated. */ + BKE_ipo_free((Ipo *)id); + break; + case ID_KE: + BKE_key_free((Key *)id); + break; + case ID_WO: + BKE_world_free((World *)id); + break; + case ID_SCR: + BKE_screen_free((bScreen *)id); + break; + case ID_VF: + BKE_vfont_free((VFont *)id); + break; + case ID_TXT: + BKE_text_free((Text *)id); + break; + case ID_SPK: + BKE_speaker_free((Speaker *)id); + break; + case ID_SO: + BKE_sound_free((bSound *)id); + break; + case ID_GR: + BKE_group_free((Group *)id); + break; + case ID_AR: + BKE_armature_free((bArmature *)id); + break; + case ID_AC: + BKE_action_free((bAction *)id); + break; + case ID_NT: + ntreeFreeTree((bNodeTree *)id); + break; + case ID_BR: + BKE_brush_free((Brush *)id); + break; + case ID_PA: + BKE_particlesettings_free((ParticleSettings *)id); + break; + case ID_WM: + if (free_windowmanager_cb) + free_windowmanager_cb(NULL, (wmWindowManager *)id); + break; + case ID_GD: + BKE_gpencil_free((bGPdata *)id); + break; + case ID_MC: + BKE_movieclip_free((MovieClip *)id); + break; + case ID_MSK: + BKE_mask_free((Mask *)id); + break; + case ID_LS: + BKE_linestyle_free((FreestyleLineStyle *)id); + break; + case ID_PAL: + BKE_palette_free((Palette *)id); + break; + case ID_PC: + BKE_paint_curve_free((PaintCurve *)id); + break; + } + + /* avoid notifying on removed data */ + BKE_main_lock(bmain); + + if (free_notifier_reference_cb) { + free_notifier_reference_cb(id); + } + + if (remap_editor_id_reference_cb) { + remap_editor_id_reference_cb(id, NULL); + } + + BLI_remlink(lb, id); + + BKE_libblock_free_data(bmain, id); + BKE_main_unlock(bmain); + + MEM_freeN(id); +} + +void BKE_libblock_free(Main *bmain, void *idv) +{ + BKE_libblock_free_ex(bmain, idv, true); +} + +void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ +{ + ID *id = idv; + + id_us_min(id); + + /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object. + * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes, + * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets + * fully unlinked. + * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO. + */ + if ((GS(id->name) == ID_OB) && (id->us == 1)) { + id_us_clear_real(id); + } + + if (id->us == 0) { + BKE_libblock_unlink(bmain, id, false); + + BKE_libblock_free(bmain, id); + } +} + +void BKE_libblock_delete(Main *bmain, void *idv) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int base_count, i; + + base_count = set_listbasepointers(bmain, lbarray); + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + + /* First tag all datablocks directly from target lib. + * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects). + * Avoids to have to loop twice. */ + for (i = 0; i < base_count; i++) { + ListBase *lb = lbarray[i]; + ID *id; + + for (id = lb->first; id; id = id->next) { + /* Note: in case we delete a library, we also delete all its datablocks! */ + if ((id == (ID *)idv) || (id->lib == (Library *)idv) || (id->tag & LIB_TAG_DOIT)) { + id->tag |= LIB_TAG_DOIT; + /* Will tag 'never NULL' users of this ID too. + * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect (and proxy!) + * links, this can lead to nasty crashing here in second, actual deleting loop. + * Also, this will also flag users of deleted data that cannot be unlinked + * (object using deleted obdata, etc.), so that they also get deleted. */ + BKE_libblock_remap(bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE); + } + } + } + + /* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones, have been already cleared + * when we reach it (e.g. Objects being processed before meshes, they'll have already released their 'reference' + * over meshes when we come to freeing obdata). */ + for (i = base_count; i--; ) { + ListBase *lb = lbarray[i]; + ID *id, *id_next; + + for (id = lb->first; id; id = id_next) { + id_next = id->next; + if (id->tag & LIB_TAG_DOIT) { + if (id->us != 0) { +#ifdef DEBUG_PRINT + printf("%s: deleting %s (%d)\n", __func__, id->name, id->us); +#endif + BLI_assert(id->us == 0); + } + BKE_libblock_free(bmain, id); + } + } + } +} diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 5a1dfc04045..30dc48819e9 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -125,26 +125,25 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name) return linestyle; } +/** Free (or release) any data used by this linestyle (does not free the linestyle itself). */ void BKE_linestyle_free(FreestyleLineStyle *linestyle) { LineStyleModifier *m; - - MTex *mtex; int a; + BKE_animdata_free(&linestyle->id, false); + for (a = 0; a < MAX_MTEX; a++) { - mtex = linestyle->mtex[a]; - if (mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); + MEM_SAFE_FREE(linestyle->mtex[a]); } + + /* is no lib link block, but linestyle extension */ if (linestyle->nodetree) { ntreeFreeTree(linestyle->nodetree); MEM_freeN(linestyle->nodetree); + linestyle->nodetree = NULL; } - BKE_animdata_free(&linestyle->id); while ((m = (LineStyleModifier *)linestyle->color_modifiers.first)) BKE_linestyle_color_modifier_remove(linestyle, m); while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first)) @@ -1452,33 +1451,6 @@ char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand return NULL; } -void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob) -{ - LineStyleModifier *m; - - for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) { - if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - if (((LineStyleColorModifier_DistanceFromObject *)m)->target == ob) { - ((LineStyleColorModifier_DistanceFromObject *)m)->target = NULL; - } - } - } - for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next) { - if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - if (((LineStyleAlphaModifier_DistanceFromObject *)m)->target == ob) { - ((LineStyleAlphaModifier_DistanceFromObject *)m)->target = NULL; - } - } - } - for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next) { - if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - if (((LineStyleThicknessModifier_DistanceFromObject *)m)->target == ob) { - ((LineStyleThicknessModifier_DistanceFromObject *)m)->target = NULL; - } - } - } -} - bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes) { if (use_shading_nodes) { diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 930a3c487ec..94e53755ac4 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -1010,63 +1010,10 @@ void BKE_mask_layer_free_list(ListBase *masklayers) } } -/** free for temp copy, but don't manage unlinking from other pointers */ -void BKE_mask_free_nolib(Mask *mask) +/** Free (or release) any data used by this mask (does not free the mask itself). */ +void BKE_mask_free(Mask *mask) { - BKE_mask_layer_free_list(&mask->masklayers); -} - -void BKE_mask_free(Main *bmain, Mask *mask) -{ - bScreen *scr; - ScrArea *area; - SpaceLink *sl; - Scene *scene; - - for (scr = bmain->screen.first; scr; scr = scr->id.next) { - for (area = scr->areabase.first; area; area = area->next) { - for (sl = area->spacedata.first; sl; sl = sl->next) { - switch (sl->spacetype) { - case SPACE_CLIP: - { - SpaceClip *sc = (SpaceClip *)sl; - - if (sc->mask_info.mask == mask) { - sc->mask_info.mask = NULL; - } - break; - } - case SPACE_IMAGE: - { - SpaceImage *sima = (SpaceImage *)sl; - - if (sima->mask_info.mask == mask) { - sima->mask_info.mask = NULL; - } - break; - } - } - } - } - } - - for (scene = bmain->scene.first; scene; scene = scene->id.next) { - if (scene->ed) { - Sequence *seq; - - SEQ_BEGIN (scene->ed, seq) - { - if (seq->mask == mask) { - seq->mask = NULL; - } - } - SEQ_END - } - } - - FOREACH_NODETREE(bmain, ntree, id) { - BKE_node_tree_unlink_id((ID *)mask, ntree); - } FOREACH_NODETREE_END + BKE_animdata_free((ID *)mask, false); /* free mask data */ BKE_mask_layer_free_list(&mask->masklayers); diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 30f82a50ed9..db5ac54ada9 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -81,47 +81,33 @@ void init_def_material(void) BKE_material_init(&defmaterial); } -/* not material itself */ +/** Free (or release) any data used by this material (does not free the material itself). */ void BKE_material_free(Material *ma) { - BKE_material_free_ex(ma, true); -} - -/* not material itself */ -void BKE_material_free_ex(Material *ma, bool do_id_user) -{ - MTex *mtex; int a; + + BKE_animdata_free((ID *)ma, false); for (a = 0; a < MAX_MTEX; a++) { - mtex = ma->mtex[a]; - if (do_id_user && mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); + MEM_SAFE_FREE(ma->mtex[a]); } - if (ma->ramp_col) MEM_freeN(ma->ramp_col); - if (ma->ramp_spec) MEM_freeN(ma->ramp_spec); - - BKE_animdata_free((ID *)ma); - - if (ma->preview) - BKE_previewimg_free(&ma->preview); - BKE_icon_id_delete((struct ID *)ma); - ma->id.icon_id = 0; + MEM_SAFE_FREE(ma->ramp_col); + MEM_SAFE_FREE(ma->ramp_spec); /* is no lib link block, but material extension */ if (ma->nodetree) { - ntreeFreeTree_ex(ma->nodetree, do_id_user); + ntreeFreeTree(ma->nodetree); MEM_freeN(ma->nodetree); + ma->nodetree = NULL; } - if (ma->texpaintslot) - MEM_freeN(ma->texpaintslot); + MEM_SAFE_FREE(ma->texpaintslot); + + GPU_material_free(&ma->gpumaterial); - if (ma->gpumaterial.first) - GPU_material_free(&ma->gpumaterial); + BKE_icon_id_delete((ID *)ma); + BKE_previewimg_free(&ma->preview); } void BKE_material_init(Material *ma) @@ -1840,7 +1826,7 @@ void free_matcopybuf(void) matcopybuf.ramp_spec = NULL; if (matcopybuf.nodetree) { - ntreeFreeTree_ex(matcopybuf.nodetree, false); + ntreeFreeTree(matcopybuf.nodetree); MEM_freeN(matcopybuf.nodetree); matcopybuf.nodetree = NULL; } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index d7019aa8458..685cd35fc20 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -66,28 +66,13 @@ /* Functions */ -void BKE_mball_unlink(MetaBall *mb) +/** Free (or release) any data used by this mball (does not free the mball itself). */ +void BKE_mball_free(MetaBall *mb) { - int a; - - for (a = 0; a < mb->totcol; a++) { - if (mb->mat[a]) - id_us_min(&mb->mat[a]->id); - mb->mat[a] = NULL; - } -} + BKE_animdata_free((ID *)mb, false); + MEM_SAFE_FREE(mb->mat); -/* do not free mball itself */ -void BKE_mball_free(MetaBall *mb) -{ - BKE_mball_unlink(mb); - - if (mb->adt) { - BKE_animdata_free((ID *)mb); - mb->adt = NULL; - } - if (mb->mat) MEM_freeN(mb->mat); BLI_freelistN(&mb->elems); if (mb->disp.first) BKE_displist_free(&mb->disp); } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 2af78cca79f..4e47dfcce74 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -432,33 +432,11 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me) * we need a more generic method, like the expand() functions in * readfile.c */ -void BKE_mesh_unlink(Mesh *me) -{ - int a; - - if (me == NULL) return; - - if (me->mat) { - for (a = 0; a < me->totcol; a++) { - if (me->mat[a]) - id_us_min(&me->mat[a]->id); - me->mat[a] = NULL; - } - } - if (me->key) { - id_us_min(&me->key->id); - } - me->key = NULL; - - if (me->texcomesh) me->texcomesh = NULL; -} - -/* do not free mesh itself */ -void BKE_mesh_free(Mesh *me, int unlink) +/** Free (or release) any data used by this mesh (does not free the mesh itself). */ +void BKE_mesh_free(Mesh *me) { - if (unlink) - BKE_mesh_unlink(me); + BKE_animdata_free(&me->id, false); CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); @@ -466,16 +444,10 @@ void BKE_mesh_free(Mesh *me, int unlink) CustomData_free(&me->ldata, me->totloop); CustomData_free(&me->pdata, me->totpoly); - if (me->adt) { - BKE_animdata_free(&me->id); - me->adt = NULL; - } - - if (me->mat) MEM_freeN(me->mat); - - if (me->bb) MEM_freeN(me->bb); - if (me->mselect) MEM_freeN(me->mselect); - if (me->edit_btmesh) MEM_freeN(me->edit_btmesh); + MEM_SAFE_FREE(me->mat); + MEM_SAFE_FREE(me->bb); + MEM_SAFE_FREE(me->mselect); + MEM_SAFE_FREE(me->edit_btmesh); } static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata) diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index d2bfcfb0887..5f667732b04 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1248,7 +1248,7 @@ static void free_buffers(MovieClip *clip) clip->anim = NULL; } - BKE_animdata_free((ID *) clip); + BKE_animdata_free((ID *) clip, false); } void BKE_movieclip_clear_cache(MovieClip *clip) @@ -1482,8 +1482,10 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip, ImBuf *ibuf, stru } } +/** Free (or release) any data used by this movie clip (does not free the clip itself). */ void BKE_movieclip_free(MovieClip *clip) { + /* Also frees animdata. */ free_buffers(clip); BKE_tracking_free(&clip->tracking); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 2b381f6ff0b..d78ddc41e97 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1782,21 +1782,21 @@ static void free_localized_node_groups(bNodeTree *ntree) for (node = ntree->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP && node->id) { bNodeTree *ngroup = (bNodeTree *)node->id; - ntreeFreeTree_ex(ngroup, false); + ntreeFreeTree(ngroup); MEM_freeN(ngroup); } } } -/* do not free ntree itself here, BKE_libblock_free calls this function too */ -void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user) +/** Free (or release) any data used by this nodetree (does not free the nodetree itself). */ +void ntreeFreeTree(bNodeTree *ntree) { bNodeTree *tntree; bNode *node, *next; bNodeSocket *sock, *nextsock; - - if (ntree == NULL) return; - + + BKE_animdata_free((ID *)ntree, false); + /* XXX hack! node trees should not store execution graphs at all. * This should be removed when old tree types no longer require it. * Currently the execution data for texture nodes remains in the tree @@ -1820,29 +1820,10 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user) /* unregister associated RNA types */ ntreeInterfaceTypeFree(ntree); - BKE_animdata_free((ID *)ntree); - - id_us_min((ID *)ntree->gpd); - BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */ for (node = ntree->nodes.first; node; node = next) { next = node->next; - - /* ntreeUserIncrefID inline */ - - /* XXX, this is correct, however when freeing the entire database - * this ends up accessing freed data which isn't properly unlinking - * its self from scene nodes, SO - for now prefer invalid usercounts - * on free rather then bad memory access - Campbell */ -#if 0 - if (do_id_user) { - id_us_min(node->id); - } -#else - (void)do_id_user; -#endif - node_free_node_ex(ntree, node, false, false); } @@ -1874,11 +1855,6 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user) BKE_libblock_free_data(G.main, &ntree->id); } } -/* same as ntreeFreeTree_ex but always manage users */ -void ntreeFreeTree(bNodeTree *ntree) -{ - ntreeFreeTree_ex(ntree, true); -} void ntreeFreeCache(bNodeTree *ntree) { @@ -2165,7 +2141,7 @@ void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree) if (ntree->typeinfo->local_merge) ntree->typeinfo->local_merge(localtree, ntree); - ntreeFreeTree_ex(localtree, false); + ntreeFreeTree(localtree); MEM_freeN(localtree); } } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 65ee153e00b..d4ba70ee0a6 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -317,14 +317,14 @@ void BKE_object_free_derived_caches(Object *ob) if (ob->type == OB_MESH) { Mesh *me = ob->data; - if (me->bb) { + if (me && me->bb) { me->bb->flag |= BOUNDBOX_DIRTY; } } else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { Curve *cu = ob->data; - if (cu->bb) { + if (cu && cu->bb) { cu->bb->flag |= BOUNDBOX_DIRTY; } } @@ -393,77 +393,52 @@ void BKE_object_free_caches(Object *object) } } -/* do not free object itself */ -void BKE_object_free_ex(Object *ob, bool do_id_user) +/** Free (or release) any data used by this object (does not free the object itself). */ +void BKE_object_free(Object *ob) { - int a; - + BKE_animdata_free((ID *)ob, false); + BKE_object_free_modifiers(ob); - - /* disconnect specific data, but not for lib data (might be indirect data, can get relinked) */ - if (ob->data) { - ID *id = ob->data; - id_us_min(id); - if (id->us == 0 && id->lib == NULL) { - switch (ob->type) { - case OB_MESH: - BKE_mesh_unlink((Mesh *)id); - break; - case OB_CURVE: - BKE_curve_unlink((Curve *)id); - break; - case OB_MBALL: - BKE_mball_unlink((MetaBall *)id); - break; - } - } - ob->data = NULL; - } - if (ob->mat) { - for (a = 0; a < ob->totcol; a++) { - if (ob->mat[a]) - id_us_min(&ob->mat[a]->id); - } - MEM_freeN(ob->mat); + MEM_SAFE_FREE(ob->mat); + MEM_SAFE_FREE(ob->matbits); + MEM_SAFE_FREE(ob->iuser); + MEM_SAFE_FREE(ob->bb); + + BLI_freelistN(&ob->defbase); + if (ob->pose) { + BKE_pose_free_ex(ob->pose, false); + ob->pose = NULL; } - if (ob->matbits) MEM_freeN(ob->matbits); - ob->mat = NULL; - ob->matbits = NULL; - if (ob->iuser) MEM_freeN(ob->iuser); - ob->iuser = NULL; - if (ob->bb) MEM_freeN(ob->bb); - ob->bb = NULL; - if (ob->adt) BKE_animdata_free((ID *)ob); - if (ob->poselib) - id_us_min(&ob->poselib->id); - if (ob->gpd) - id_us_min(&ob->gpd->id); - if (ob->defbase.first) - BLI_freelistN(&ob->defbase); - if (ob->pose) - BKE_pose_free_ex(ob->pose, do_id_user); - if (ob->mpath) + if (ob->mpath) { animviz_free_motionpath(ob->mpath); + ob->mpath = NULL; + } BKE_bproperty_free_list(&ob->prop); - + free_sensors(&ob->sensors); free_controllers(&ob->controllers); free_actuators(&ob->actuators); - BKE_constraints_free_ex(&ob->constraints, do_id_user); + BKE_constraints_free_ex(&ob->constraints, false); free_partdeflect(ob->pd); BKE_rigidbody_free_object(ob); BKE_rigidbody_free_constraint(ob); - if (ob->soft) sbFree(ob->soft); - if (ob->bsoft) bsbFree(ob->bsoft); - if (ob->gpulamp.first) GPU_lamp_free(ob); + if (ob->soft) { + sbFree(ob->soft); + ob->soft = NULL; + } + if (ob->bsoft) { + bsbFree(ob->bsoft); + ob->bsoft = NULL; + } + GPU_lamp_free(ob); BKE_sculptsession_free(ob); - if (ob->pc_ids.first) BLI_freelistN(&ob->pc_ids); + BLI_freelistN(&ob->pc_ids); BLI_freelistN(&ob->lodlevels); @@ -473,398 +448,12 @@ void BKE_object_free_ex(Object *ob, bool do_id_user) if (ob->curve_cache->path) free_path(ob->curve_cache->path); MEM_freeN(ob->curve_cache); + ob->curve_cache = NULL; } BKE_previewimg_free(&ob->preview); } -void BKE_object_free(Object *ob) -{ - BKE_object_free_ex(ob, true); -} - -static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin, int UNUSED(cd_flag)) -{ - Object *unlinkOb = userData; - - if (*obpoin == unlinkOb) { - *obpoin = NULL; - // XXX: should this just be OB_RECALC_DATA? - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } -} - -void BKE_object_unlink(Main *bmain, Object *ob) -{ - Object *obt; - Material *mat; - World *wrld; - bScreen *sc; - Scene *sce; - SceneRenderLayer *srl; - FreestyleLineSet *lineset; - bNodeTree *ntree; - Curve *cu; - Tex *tex; - Group *group; - Camera *camera; - bConstraint *con; - //bActionStrip *strip; // XXX animsys - ModifierData *md; - ARegion *ar; - RegionView3D *rv3d; - LodLevel *lod; - int a, found; - - unlink_controllers(&ob->controllers); - unlink_actuators(&ob->actuators); - - /* check all objects: parents en bevels and fields, also from libraries */ - /* FIXME: need to check all animation blocks (drivers) */ - obt = bmain->object.first; - while (obt) { - if (obt->proxy == ob) - obt->proxy = NULL; - if (obt->proxy_from == ob) { - obt->proxy_from = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB); - } - if (obt->proxy_group == ob) - obt->proxy_group = NULL; - - if (obt->parent == ob) { - obt->parent = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } - - modifiers_foreachObjectLink(obt, unlink_object__unlinkModifierLinks, ob); - - if (ELEM(obt->type, OB_CURVE, OB_FONT)) { - cu = obt->data; - - if (cu->bevobj == ob) { - cu->bevobj = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } - if (cu->taperobj == ob) { - cu->taperobj = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } - if (cu->textoncurve == ob) { - cu->textoncurve = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } - } - else if (obt->type == OB_ARMATURE && obt->pose) { - bPoseChannel *pchan; - for (pchan = obt->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == ob) { - ct->tar = NULL; - ct->subtarget[0] = '\0'; - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } - } - if (pchan->custom == ob) - pchan->custom = NULL; - } - } - else if (ELEM(OB_MBALL, ob->type, obt->type)) { - if (BKE_mball_is_basis_for(obt, ob)) - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - - sca_remove_ob_poin(obt, ob); - - for (con = obt->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == ob) { - ct->tar = NULL; - ct->subtarget[0] = '\0'; - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } - } - - /* object is deflector or field */ - if (ob->pd) { - if (obt->soft) - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - - /* cloth */ - for (md = obt->modifiers.first; md; md = md->next) - if (md->type == eModifierType_Cloth) - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - - /* strips */ -#if 0 // XXX old animation system - for (strip = obt->nlastrips.first; strip; strip = strip->next) { - if (strip->object == ob) - strip->object = NULL; - - if (strip->modifiers.first) { - bActionModifier *amod; - for (amod = strip->modifiers.first; amod; amod = amod->next) - if (amod->ob == ob) - amod->ob = NULL; - } - } -#endif // XXX old animation system - - /* particle systems */ - if (obt->particlesystem.first) { - ParticleSystem *tpsys = obt->particlesystem.first; - for (; tpsys; tpsys = tpsys->next) { - BoidState *state = NULL; - BoidRule *rule = NULL; - - ParticleTarget *pt = tpsys->targets.first; - for (; pt; pt = pt->next) { - if (pt->ob == ob) { - pt->ob = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - break; - } - } - - if (tpsys->target_ob == ob) { - tpsys->target_ob = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - - if (tpsys->part->dup_ob == ob) - tpsys->part->dup_ob = NULL; - - if (tpsys->part->phystype == PART_PHYS_BOIDS) { - ParticleData *pa; - BoidParticle *bpa; - int p; - - for (p = 0, pa = tpsys->particles; p < tpsys->totpart; p++, pa++) { - bpa = pa->boid; - if (bpa->ground == ob) - bpa->ground = NULL; - } - } - if (tpsys->part->boids) { - for (state = tpsys->part->boids->states.first; state; state = state->next) { - for (rule = state->rules.first; rule; rule = rule->next) { - if (rule->type == eBoidRuleType_Avoid) { - BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule; - if (gabr->ob == ob) - gabr->ob = NULL; - } - else if (rule->type == eBoidRuleType_FollowLeader) { - BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule; - if (flbr->ob == ob) - flbr->ob = NULL; - } - } - } - } - - if (tpsys->parent == ob) - tpsys->parent = NULL; - } - if (ob->pd) - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - - /* levels of detail */ - for (lod = obt->lodlevels.first; lod; lod = lod->next) { - if (lod->source == ob) - lod->source = NULL; - } - - obt = obt->id.next; - } - - /* materials */ - for (mat = bmain->mat.first; mat; mat = mat->id.next) { - if (mat->nodetree) { - ntreeSwitchID(mat->nodetree, &ob->id, NULL); - } - for (a = 0; a < MAX_MTEX; a++) { - if (mat->mtex[a] && ob == mat->mtex[a]->object) { - /* actually, test for lib here... to do */ - mat->mtex[a]->object = NULL; - } - } - } - - /* node trees */ - for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) { - if (ntree->type == NTREE_SHADER) - ntreeSwitchID(ntree, &ob->id, NULL); - } - - /* textures */ - for (tex = bmain->tex.first; tex; tex = tex->id.next) { - if (tex->env && (ob == tex->env->object)) tex->env->object = NULL; - if (tex->pd && (ob == tex->pd->object)) tex->pd->object = NULL; - if (tex->vd && (ob == tex->vd->object)) tex->vd->object = NULL; - } - - /* worlds */ - wrld = bmain->world.first; - while (wrld) { - if (wrld->id.lib == NULL) { - for (a = 0; a < MAX_MTEX; a++) { - if (wrld->mtex[a] && ob == wrld->mtex[a]->object) - wrld->mtex[a]->object = NULL; - } - } - - wrld = wrld->id.next; - } - - /* scenes */ - sce = bmain->scene.first; - while (sce) { - if (sce->id.lib == NULL) { - if (sce->camera == ob) sce->camera = NULL; - if (sce->toolsettings->skgen_template == ob) sce->toolsettings->skgen_template = NULL; - if (sce->toolsettings->particle.object == ob) sce->toolsettings->particle.object = NULL; - if (sce->toolsettings->particle.shape_object == ob) sce->toolsettings->particle.shape_object = NULL; - -#ifdef DURIAN_CAMERA_SWITCH - { - TimeMarker *m; - - for (m = sce->markers.first; m; m = m->next) { - if (m->camera == ob) - m->camera = NULL; - } - } -#endif - if (sce->ed) { - Sequence *seq; - SEQ_BEGIN(sce->ed, seq) - { - if (seq->scene_camera == ob) { - seq->scene_camera = NULL; - } - } - SEQ_END - } - - for (srl = sce->r.layers.first; srl; srl = srl->next) { - for (lineset = (FreestyleLineSet *)srl->freestyleConfig.linesets.first; - lineset; lineset = lineset->next) - { - if (lineset->linestyle) { - BKE_linestyle_target_object_unlink(lineset->linestyle, ob); - } - } - } - } - - sce = sce->id.next; - } - - /* screens */ - sc = bmain->screen.first; - while (sc) { - ScrArea *sa = sc->areabase.first; - while (sa) { - SpaceLink *sl; - - for (sl = sa->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *) sl; - - /* found doesn't need to be set here */ - if (v3d->ob_centre == ob) { - v3d->ob_centre = NULL; - v3d->ob_centre_bone[0] = '\0'; - } - if (v3d->localvd && v3d->localvd->ob_centre == ob) { - v3d->localvd->ob_centre = NULL; - v3d->localvd->ob_centre_bone[0] = '\0'; - } - - found = 0; - if (v3d->camera == ob) { - v3d->camera = NULL; - found = 1; - } - if (v3d->localvd && v3d->localvd->camera == ob) { - v3d->localvd->camera = NULL; - found += 2; - } - - if (found) { - if (sa->spacetype == SPACE_VIEW3D) { - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype == RGN_TYPE_WINDOW) { - rv3d = (RegionView3D *)ar->regiondata; - if (found == 1 || found == 3) { - if (rv3d->persp == RV3D_CAMOB) - rv3d->persp = RV3D_PERSP; - } - if (found == 2 || found == 3) { - if (rv3d->localvd && rv3d->localvd->persp == RV3D_CAMOB) - rv3d->localvd->persp = RV3D_PERSP; - } - } - } - } - } - } -#if 0 - else if (ELEM(sl->spacetype, SPACE_OUTLINER, SPACE_BUTS, SPACE_NODE)) { - /* now handled by WM_main_remove_editor_id_reference */ - } -#endif - } - - sa = sa->next; - } - sc = sc->id.next; - } - - /* groups */ - group = bmain->group.first; - while (group) { - BKE_group_object_unlink(group, ob, NULL, NULL); - group = group->id.next; - } - - /* cameras */ - camera = bmain->camera.first; - while (camera) { - if (camera->dof_ob == ob) { - camera->dof_ob = NULL; - } - camera = camera->id.next; - } -} - /* actual check for internal data, not context or flags */ bool BKE_object_is_in_editmode(Object *ob) { diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 3a2663c5d48..8c1502643c5 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -298,13 +298,11 @@ void BKE_paint_brush_set(Paint *p, Brush *br) } } +/** Free (or release) any data used by this paint curve (does not free the pcurve itself). */ void BKE_paint_curve_free(PaintCurve *pc) { - if (pc->points) { - MEM_freeN(pc->points); - pc->points = NULL; - pc->tot_points = 0; - } + MEM_SAFE_FREE(pc->points); + pc->tot_points = 0; } PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name) @@ -378,6 +376,7 @@ Palette *BKE_palette_add(Main *bmain, const char *name) return palette; } +/** Free (or release) any data used by this palette (does not free the palette itself). */ void BKE_palette_free(Palette *palette) { BLI_freelistN(&palette->colors); @@ -493,8 +492,6 @@ void BKE_paint_init(Scene *sce, PaintMode mode, const char col[3]) void BKE_paint_free(Paint *paint) { - id_us_min((ID *)paint->brush); - id_us_min((ID *)paint->palette); curvemapping_free(paint->cavity_curve); } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 25dd7fff380..633227d68f3 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -376,12 +376,17 @@ static void fluid_free_settings(SPHFluidSettings *fluid) MEM_freeN(fluid); } +/** Free (or release) any data used by this particle settings (does not free the partsett itself). */ void BKE_particlesettings_free(ParticleSettings *part) { - MTex *mtex; int a; - BKE_animdata_free(&part->id); + + BKE_animdata_free((ID *)part, false); + for (a = 0; a < MAX_MTEX; a++) { + MEM_SAFE_FREE(part->mtex[a]); + } + if (part->clumpcurve) curvemapping_free(part->clumpcurve); if (part->roughcurve) @@ -390,21 +395,12 @@ void BKE_particlesettings_free(ParticleSettings *part) free_partdeflect(part->pd); free_partdeflect(part->pd2); - if (part->effector_weights) - MEM_freeN(part->effector_weights); + MEM_SAFE_FREE(part->effector_weights); BLI_freelistN(&part->dupliweights); boid_free_settings(part->boids); fluid_free_settings(part->fluid); - - for (a = 0; a < MAX_MTEX; a++) { - mtex = part->mtex[a]; - if (mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); - } } void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics) @@ -573,10 +569,7 @@ void psys_free(Object *ob, ParticleSystem *psys) if (!nr) ob->transflag &= ~OB_DUPLIPARTS; - if (psys->part) { - id_us_min(&psys->part->id); - psys->part = NULL; - } + psys->part = NULL; BKE_ptcache_free_list(&psys->ptcaches); psys->pointcache = NULL; diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index e90a39e8c0e..a468420f87d 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -653,77 +653,6 @@ void set_sca_new_poins(void) } } -void sca_remove_ob_poin(Object *obt, Object *ob) -{ - bSensor *sens; - bMessageSensor *ms; - bActuator *act; - bCameraActuator *ca; - bObjectActuator *oa; - bSceneActuator *sa; - bEditObjectActuator *eoa; - bPropertyActuator *pa; - bMessageActuator *ma; - bParentActuator *para; - bArmatureActuator *aa; - bSteeringActuator *sta; - - - sens= obt->sensors.first; - while (sens) { - switch (sens->type) { - case SENS_MESSAGE: - ms= sens->data; - if (ms->fromObject==ob) ms->fromObject= NULL; - } - sens= sens->next; - } - - act= obt->actuators.first; - while (act) { - switch (act->type) { - case ACT_CAMERA: - ca= act->data; - if (ca->ob==ob) ca->ob= NULL; - break; - case ACT_OBJECT: - oa= act->data; - if (oa->reference==ob) oa->reference= NULL; - break; - case ACT_PROPERTY: - pa= act->data; - if (pa->ob==ob) pa->ob= NULL; - break; - case ACT_SCENE: - sa= act->data; - if (sa->camera==ob) sa->camera= NULL; - break; - case ACT_EDIT_OBJECT: - eoa= act->data; - if (eoa->ob==ob) eoa->ob= NULL; - break; - case ACT_MESSAGE: - ma= act->data; - if (ma->toObject==ob) ma->toObject= NULL; - break; - case ACT_PARENT: - para = act->data; - if (para->ob==ob) para->ob = NULL; - break; - case ACT_ARMATURE: - aa = act->data; - if (aa->target == ob) aa->target = NULL; - if (aa->subtarget == ob) aa->subtarget = NULL; - break; - case ACT_STEERING: - sta = act->data; - if (sta->navmesh == ob) sta->navmesh = NULL; - if (sta->target == ob) sta->target = NULL; - } - act= act->next; - } -} - /* ******************** INTERFACE ******************* */ void sca_move_sensor(bSensor *sens_to_move, Object *ob, int move_up) { diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index a3393b6b9c0..0e8efca04d0 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -357,41 +357,34 @@ void BKE_scene_groups_relink(Scene *sce) BKE_rigidbody_world_groups_relink(sce->rigidbody_world); } -/* do not free scene itself */ +/** Free (or release) any data used by this scene (does not free the scene itself). */ void BKE_scene_free(Scene *sce) { - Base *base; SceneRenderLayer *srl; + BKE_animdata_free((ID *)sce, false); + /* check all sequences */ BKE_sequencer_clear_scene_in_allseqs(G.main, sce); - base = sce->base.first; - while (base) { - id_us_min(&base->object->id); - base = base->next; - } - /* do not free objects! */ - - if (sce->gpd) { -#if 0 /* removed since this can be invalid memory when freeing everything */ - /* since the grease pencil data is freed before the scene. - * since grease pencil data is not (yet?), shared between objects - * its probably safe not to do this, some save and reload will free this. */ - id_us_min(&sce->gpd->id); -#endif - sce->gpd = NULL; - } - + sce->basact = NULL; BLI_freelistN(&sce->base); BKE_sequencer_editing_free(sce); - BKE_animdata_free((ID *)sce); BKE_keyingsets_free(&sce->keyingsets); - - if (sce->rigidbody_world) + + /* is no lib link block, but scene extension */ + if (sce->nodetree) { + ntreeFreeTree(sce->nodetree); + MEM_freeN(sce->nodetree); + sce->nodetree = NULL; + } + + if (sce->rigidbody_world) { BKE_rigidbody_free_world(sce->rigidbody_world); - + sce->rigidbody_world = NULL; + } + if (sce->r.avicodecdata) { free_avicodecdata(sce->r.avicodecdata); MEM_freeN(sce->r.avicodecdata); @@ -444,15 +437,8 @@ void BKE_scene_free(Scene *sce) if (sce->depsgraph) DEG_graph_free(sce->depsgraph); - if (sce->nodetree) { - ntreeFreeTree(sce->nodetree); - MEM_freeN(sce->nodetree); - } - - if (sce->stats) - MEM_freeN(sce->stats); - if (sce->fps_info) - MEM_freeN(sce->fps_info); + MEM_SAFE_FREE(sce->stats); + MEM_SAFE_FREE(sce->fps_info); BKE_sound_destroy_scene(sce); @@ -904,40 +890,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name) return NULL; } -void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce) -{ - Scene *sce1; - bScreen *screen; - - /* check all sets */ - for (sce1 = bmain->scene.first; sce1; sce1 = sce1->id.next) - if (sce1->set == sce) - sce1->set = NULL; - - for (sce1 = bmain->scene.first; sce1; sce1 = sce1->id.next) { - bNode *node; - - if (sce1 == sce || !sce1->nodetree) - continue; - - for (node = sce1->nodetree->nodes.first; node; node = node->next) { - if (node->id == &sce->id) - node->id = NULL; - } - } - - /* all screens */ - for (screen = bmain->screen.first; screen; screen = screen->id.next) { - if (screen->scene == sce) { - screen->scene = newsce; - } - - /* editors are handled by WM_main_remove_editor_id_reference */ - } - - BKE_libblock_free(bmain, sce); -} - /* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, Scene **scene, int val, Base **base, Object **ob) @@ -1193,6 +1145,8 @@ void BKE_scene_base_unlink(Scene *sce, Base *base) BKE_rigidbody_remove_object(sce, base->object); BLI_remlink(&sce->base, base); + if (sce->basact == base) + sce->basact = NULL; } void BKE_scene_base_deselect_all(Scene *sce) diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 139c6670f74..857bd5447c8 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -273,17 +273,18 @@ void BKE_spacedata_draw_locks(int set) } } -static void (*spacedata_id_unref_cb)(struct SpaceLink *sl, const struct ID *id) = NULL; +static void (*spacedata_id_remap_cb)(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id) = NULL; -void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *)) +void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *sa, SpaceLink *sl, ID *, ID *)) { - spacedata_id_unref_cb = func; + spacedata_id_remap_cb = func; } -void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id) +/* UNUSED!!! */ +void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id) { - if (spacedata_id_unref_cb) { - spacedata_id_unref_cb(sl, id); + if (spacedata_id_remap_cb) { + spacedata_id_remap_cb(sa, sl, id, NULL); } } @@ -358,11 +359,13 @@ void BKE_screen_area_free(ScrArea *sa) BLI_freelistN(&sa->actionzones); } -/* don't free screen itself */ +/** Free (or release) any data used by this screen (does not free the screen itself). */ void BKE_screen_free(bScreen *sc) { ScrArea *sa, *san; ARegion *ar; + + /* No animdata here. */ for (ar = sc->regionbase.first; ar; ar = ar->next) BKE_area_region_free(NULL, ar); diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index c82f3a3af23..5ef502e0182 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -3092,7 +3092,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr BKE_maskrasterize_handle_init(mr_handle, mask_temp, context->rectx, context->recty, true, true, true); - BKE_mask_free_nolib(mask_temp); + BKE_mask_free(mask_temp); MEM_freeN(mask_temp); BKE_maskrasterize_buffer(mr_handle, context->rectx, context->recty, maskbuf); @@ -5154,7 +5154,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad info = AUD_getInfo(sound->playback_handle); if (info.specs.channels == AUD_CHANNELS_INVALID) { - BKE_sound_delete(bmain, sound); + BKE_libblock_free(bmain, sound); #if 0 if (op) BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index b016f8a49ed..414be73e234 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -123,8 +123,11 @@ bSound *BKE_sound_new_file_exists(struct Main *bmain, const char *filepath) return BKE_sound_new_file_exists_ex(bmain, filepath, NULL); } +/** Free (or release) any data used by this sound (does not free the sound itself). */ void BKE_sound_free(bSound *sound) { + /* No animdata here. */ + if (sound->packedfile) { freePackedFile(sound->packedfile); sound->packedfile = NULL; @@ -148,8 +151,7 @@ void BKE_sound_free(bSound *sound) BLI_spin_end(sound->spinlock); MEM_freeN(sound->spinlock); sound->spinlock = NULL; - } - + } #endif /* WITH_AUDASPACE */ } @@ -315,15 +317,6 @@ bSound *BKE_sound_new_limiter(struct Main *bmain, bSound *source, float start, f } #endif -void BKE_sound_delete(struct Main *bmain, bSound *sound) -{ - if (sound) { - BKE_sound_free(sound); - - BKE_libblock_free(bmain, sound); - } -} - void BKE_sound_cache(bSound *sound) { sound->flags |= SOUND_FLAGS_CACHING; diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index c452065fbad..e5075a2d382 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -141,8 +141,5 @@ void BKE_speaker_make_local(Speaker *spk) void BKE_speaker_free(Speaker *spk) { - if (spk->sound) - id_us_min(&spk->sound->id); - - BKE_animdata_free((ID *)spk); + BKE_animdata_free((ID *)spk, false); } diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 6def9e3e503..594f9dffbee 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -171,14 +171,17 @@ void BKE_text_free_lines(Text *text) text->curl = text->sell = NULL; } +/** Free (or release) any data used by this text (does not free the text itself). */ void BKE_text_free(Text *text) { + /* No animdata here. */ + BKE_text_free_lines(text); - if (text->name) MEM_freeN(text->name); - MEM_freeN(text->undo_buf); + MEM_SAFE_FREE(text->name); + MEM_SAFE_FREE(text->undo_buf); #ifdef WITH_PYTHON - if (text->compiled) BPY_text_free_code(text); + BPY_text_free_code(text); #endif } diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index d353042b711..9326ece7a4b 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -557,23 +557,38 @@ int colorband_element_remove(struct ColorBand *coba, int index) /* ******************* TEX ************************ */ +/** Free (or release) any data used by this texture (does not free the texure itself). */ void BKE_texture_free(Tex *tex) { - if (tex->coba) MEM_freeN(tex->coba); - if (tex->env) BKE_texture_envmap_free(tex->env); - if (tex->pd) BKE_texture_pointdensity_free(tex->pd); - if (tex->vd) BKE_texture_voxeldata_free(tex->vd); - if (tex->ot) BKE_texture_ocean_free(tex->ot); - BKE_animdata_free((struct ID *)tex); - - BKE_previewimg_free(&tex->preview); - BKE_icon_id_delete((struct ID *)tex); - tex->id.icon_id = 0; - + BKE_animdata_free((ID *)tex, false); + + /* is no lib link block, but texture extension */ if (tex->nodetree) { ntreeFreeTree(tex->nodetree); MEM_freeN(tex->nodetree); + tex->nodetree = NULL; } + + MEM_SAFE_FREE(tex->coba); + if (tex->env) { + BKE_texture_envmap_free(tex->env); + tex->env = NULL; + } + if (tex->pd) { + BKE_texture_pointdensity_free(tex->pd); + tex->pd = NULL; + } + if (tex->vd) { + BKE_texture_voxeldata_free(tex->vd); + tex->vd = NULL; + } + if (tex->ot) { + BKE_texture_ocean_free(tex->ot); + tex->ot = NULL; + } + + BKE_icon_id_delete((ID *)tex); + BKE_previewimg_free(&tex->preview); } /* ------------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 17a2e7f14fd..ec021586be5 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -52,38 +52,28 @@ #include "GPU_material.h" -void BKE_world_free_ex(World *wrld, bool do_id_user) +/** Free (or release) any data used by this world (does not free the world itself). */ +void BKE_world_free(World *wrld) { - MTex *mtex; int a; - + + BKE_animdata_free((ID *)wrld, false); + for (a = 0; a < MAX_MTEX; a++) { - mtex = wrld->mtex[a]; - if (do_id_user && mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); + MEM_SAFE_FREE(wrld->mtex[a]); } - BKE_previewimg_free(&wrld->preview); - - BKE_animdata_free((ID *)wrld); /* is no lib link block, but world extension */ if (wrld->nodetree) { - ntreeFreeTree_ex(wrld->nodetree, do_id_user); + ntreeFreeTree(wrld->nodetree); MEM_freeN(wrld->nodetree); + wrld->nodetree = NULL; } - if (wrld->gpumaterial.first) - GPU_material_free(&wrld->gpumaterial); + GPU_material_free(&wrld->gpumaterial); BKE_icon_id_delete((struct ID *)wrld); - wrld->id.icon_id = 0; -} - -void BKE_world_free(World *wrld) -{ - BKE_world_free_ex(wrld, true); + BKE_previewimg_free(&wrld->preview); } void BKE_world_init(World *wrld) diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cpp index 220b4e908a6..d6e5fdf86bb 100644 --- a/source/blender/compositor/operations/COM_MaskOperation.cpp +++ b/source/blender/compositor/operations/COM_MaskOperation.cpp @@ -94,7 +94,7 @@ void MaskOperation::initExecution() frame_iter += frame_step; } - BKE_mask_free_nolib(mask_temp); + BKE_mask_free(mask_temp); MEM_freeN(mask_temp); } } diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 8822c8511de..c98470fb194 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -2119,7 +2119,7 @@ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op)) /* remove AnimData? */ if (action_empty && nla_empty && drivers_empty) { - BKE_animdata_free(id); + BKE_animdata_free(id, true); } } diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h index 9a987d7618c..64c16605dec 100644 --- a/source/blender/editors/include/ED_buttons.h +++ b/source/blender/editors/include/ED_buttons.h @@ -37,6 +37,4 @@ bool ED_texture_context_check_particles(const struct bContext *C); bool ED_texture_context_check_linestyle(const struct bContext *C); bool ED_texture_context_check_others(const struct bContext *C); -void ED_buttons_id_unref(struct SpaceButs *sbuts, const struct ID *id); - #endif /* __ED_BUTTONS_H__ */ diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 7fe9a0c320c..f7b9d6b4f9e 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -103,8 +103,6 @@ void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNod void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree, struct Scene *scene_owner); -void ED_node_id_unref(struct SpaceNode *snode, const ID *id); - /* node_ops.c */ void ED_operatormacros_node(void); diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h index af4af8e2f5d..73ee2542247 100644 --- a/source/blender/editors/include/ED_outliner.h +++ b/source/blender/editors/include/ED_outliner.h @@ -27,10 +27,4 @@ #ifndef __ED_OUTLINER_H__ #define __ED_OUTLINER_H__ -struct ID; -struct SpaceOops; - -/* Used to check whether a given texture context is valid in current context. */ -void ED_outliner_id_unref(struct SpaceOops *so, const struct ID *id); - #endif /* __ED_OUTLINER_H__ */ diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index f143ea478c6..b6b80b93e0b 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -43,7 +43,7 @@ void ED_editors_exit(struct bContext *C); bool ED_editors_flush_edits(const struct bContext *C, bool for_render); -void ED_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id); +void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id); void ED_OT_flush_edits(struct wmOperatorType *ot); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index c23c2eed890..baab6b6100d 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -403,4 +403,6 @@ void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View #define V3D_IS_ZBUF(v3d) \ (((v3d)->flag & V3D_ZBUF_SELECT) && ((v3d)->drawtype > OB_WIRE)) +void ED_view3d_id_remap(struct View3D *v3d, const struct ID *old_id, struct ID *new_id); + #endif /* __ED_VIEW3D_H__ */ diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 8b16b2a977e..62656d75b9a 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -637,7 +637,7 @@ static void free_undo(void *um_v) MEM_freeN(me->key); } - BKE_mesh_free(me, false); + BKE_mesh_free(me); MEM_freeN(me); } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 09c9442db54..f85c76291cd 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1112,7 +1112,6 @@ void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Base *base) BKE_scene_base_unlink(scene, base); object_delete_check_glsl_update(base->object); BKE_libblock_free_us(bmain, base->object); - if (scene->basact == base) scene->basact = NULL; MEM_freeN(base); } @@ -1288,7 +1287,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, basen->object = ob; /* make sure apply works */ - BKE_animdata_free(&ob->id); + BKE_animdata_free(&ob->id, true); ob->adt = NULL; /* Proxies are not to be copied. */ @@ -1380,7 +1379,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, } } - /* The same how BKE_object_unlink detects which object proxies to clear. */ if (base->object->transflag & OB_DUPLIGROUP && base->object->dup_group) { for (object = bmain->object.first; object; object = object->id.next) { if (object->proxy_group == base->object) { diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index 76a8a68c42d..2b87a890f0f 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -43,6 +43,7 @@ #include "BKE_depsgraph.h" #include "BKE_group.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_object.h" @@ -527,7 +528,8 @@ static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op)) if (!group) return OPERATOR_CANCELLED; - BKE_group_unlink(bmain, group); + BKE_libblock_unlink(bmain, group, false); + BKE_libblock_free(bmain, group); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index f4260a0cd33..132c3fa5438 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -70,6 +70,7 @@ #include "BKE_icons.h" #include "BKE_lamp.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_node.h" @@ -830,7 +831,7 @@ static void shader_preview_free(void *customdata) /* get rid of copied material */ BLI_remlink(&pr_main->mat, sp->matcopy); - BKE_material_free_ex(sp->matcopy, false); + BKE_material_free(sp->matcopy); properties = IDP_GetProperties((ID *)sp->matcopy, false); if (properties) { @@ -862,7 +863,9 @@ static void shader_preview_free(void *customdata) /* get rid of copied world */ BLI_remlink(&pr_main->world, sp->worldcopy); - BKE_world_free_ex(sp->worldcopy, true); /* [#32865] - we need to unlink the texture copies, unlike for materials */ + /* T32865 - we need to unlink the texture copies, unlike for materials */ + BKE_libblock_relink_ex(sp->worldcopy, NULL, NULL, true); + BKE_world_free(sp->worldcopy); properties = IDP_GetProperties((ID *)sp->worldcopy, false); if (properties) { @@ -878,6 +881,7 @@ static void shader_preview_free(void *customdata) /* get rid of copied lamp */ BLI_remlink(&pr_main->lamp, sp->lampcopy); + BKE_libblock_relink_ex(sp->lampcopy, NULL, NULL, true); BKE_lamp_free(sp->lampcopy); properties = IDP_GetProperties((ID *)sp->lampcopy, false); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index a459f982ada..62aeca4b9d1 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -45,6 +45,7 @@ #include "BKE_image.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_screen.h" @@ -1755,7 +1756,9 @@ bool ED_screen_delete_scene(bContext *C, Scene *scene) ED_screen_set_scene(C, CTX_wm_screen(C), newscene); - BKE_scene_unlink(bmain, scene, newscene); + BKE_libblock_remap(bmain, scene, newscene, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); + + BKE_libblock_free(bmain, scene); return true; } diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index a4d9a920cbb..4931426d62e 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -116,7 +116,7 @@ static int sound_open_exec(bContext *C, wmOperator *op) info = AUD_getInfo(sound->playback_handle); if (info.specs.channels == AUD_CHANNELS_INVALID) { - BKE_sound_delete(bmain, sound); + BKE_libblock_free(bmain, sound); if (op->customdata) MEM_freeN(op->customdata); BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 60240109432..671d6bb083e 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -33,6 +33,7 @@ #include <stdio.h> #include "DNA_action_types.h" +#include "DNA_group_types.h" #include "DNA_scene_types.h" #include "MEM_guardedalloc.h" @@ -614,6 +615,19 @@ static void action_refresh(const bContext *C, ScrArea *sa) // XXX re-sizing y-extents of tot should go here? } +static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceAction *sact = (SpaceAction *)slink; + + if (!ELEM(GS(old_id->name), ID_GR)) { + return; + } + + if ((ID *)sact->ads.filter_grp == old_id) { + sact->ads.filter_grp = (Group *)new_id; + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_action(void) { @@ -631,7 +645,8 @@ void ED_spacetype_action(void) st->keymap = action_keymap; st->listener = action_listener; st->refresh = action_refresh; - + st->id_remap = action_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 42e2d6b90f0..5b03bdd7761 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -1180,33 +1180,3 @@ ID *buttons_context_id_path(const bContext *C) return NULL; } - -void ED_buttons_id_unref(SpaceButs *sbuts, const ID *id) -{ - if (sbuts->pinid == id) { - sbuts->pinid = NULL; - sbuts->flag &= ~SB_PIN_CONTEXT; - } - - if (sbuts->path) { - ButsContextPath *path = sbuts->path; - int i; - - for (i = 0; i < path->len; i++) { - if (path->ptr[i].id.data == id) { - break; - } - } - - if (i == path->len) { - /* pass */ - } - else if (i == 0) { - MEM_SAFE_FREE(sbuts->path); - } - else { - memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i)); - path->len = i; - } - } -} diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 126a27c36cb..e4c23ad74f8 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -45,6 +45,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "RNA_access.h" + #include "buttons_intern.h" /* own include */ /* ******************** default callbacks for buttons space ***************** */ @@ -389,6 +391,59 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier * ED_area_tag_redraw(sa); } +static void buttons_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceButs *sbuts = (SpaceButs *)slink; + + if (sbuts->pinid == old_id) { + sbuts->pinid = new_id; + if (new_id == NULL) { + sbuts->flag &= ~SB_PIN_CONTEXT; + } + } + + if (sbuts->path) { + ButsContextPath *path = sbuts->path; + int i; + + for (i = 0; i < path->len; i++) { + if (path->ptr[i].id.data == old_id) { + break; + } + } + + if (i == path->len) { + /* pass */ + } + else if (new_id == NULL) { + if (i == 0) { + MEM_SAFE_FREE(sbuts->path); + } + else { + memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i)); + path->len = i; + } + } + else { + RNA_id_pointer_create(new_id, &path->ptr[i]); + /* There is no easy way to check/make path downwards valid, just nullify it. + * Next redraw will rebuild this anyway. */ + i++; + memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i)); + path->len = i; + } + } + + if (sbuts->texuser) { + ButsContextTexture *ct = sbuts->texuser; + if ((ID *)ct->texture == old_id) { + ct->texture = (Tex *)new_id; + } + BLI_freelistN(&ct->users); + ct->user = NULL; + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_buttons(void) { @@ -406,7 +461,8 @@ void ED_spacetype_buttons(void) st->keymap = buttons_keymap; st->listener = buttons_area_listener; st->context = buttons_context; - + st->id_remap = buttons_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index e1d4e4fabc5..415839ab761 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -45,6 +45,7 @@ #include "BKE_context.h" #include "BKE_screen.h" +#include "BKE_library.h" #include "BKE_movieclip.h" #include "BKE_tracking.h" @@ -1512,6 +1513,25 @@ static void clip_properties_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED /********************* registration ********************/ +static void clip_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceClip *sclip = (SpaceClip *)slink; + + if (!ELEM(GS(old_id->name), ID_MC, ID_MSK)) { + return; + } + + if ((ID *)sclip->clip == old_id) { + sclip->clip = (MovieClip *)new_id; + id_us_ensure_real(new_id); + } + + if ((ID *)sclip->mask_info.mask == old_id) { + sclip->mask_info.mask = (Mask *)new_id; + id_us_ensure_real(new_id); + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_clip(void) { @@ -1531,6 +1551,7 @@ void ED_spacetype_clip(void) st->context = clip_context; st->dropboxes = clip_dropboxes; st->refresh = clip_refresh; + st->id_remap = clip_id_remap; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype clip region"); diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index c6a8a9753d1..a7284694f64 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -33,6 +33,7 @@ #include <stdio.h> #include "DNA_anim_types.h" +#include "DNA_group_types.h" #include "DNA_scene_types.h" #include "MEM_guardedalloc.h" @@ -627,6 +628,19 @@ static void graph_refresh(const bContext *C, ScrArea *sa) } } +static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceIpo *sgraph = (SpaceIpo *)slink; + + if (!ELEM(GS(old_id->name), ID_GR)) { + return; + } + + if ((ID *)sgraph->ads->filter_grp == old_id) { + sgraph->ads->filter_grp = (Group *)new_id; + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_ipo(void) { @@ -644,7 +658,8 @@ void ED_spacetype_ipo(void) st->keymap = graphedit_keymap; st->listener = graph_listener; st->refresh = graph_refresh; - + st->id_remap = graph_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 168f9c0dfdf..35a658eac23 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -28,6 +28,7 @@ * \ingroup spimage */ +#include "DNA_gpencil_types.h" #include "DNA_mesh_types.h" #include "DNA_mask_types.h" #include "DNA_meshdata_types.h" @@ -44,6 +45,7 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_image.h" +#include "BKE_library.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -981,6 +983,31 @@ static void image_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa } } +static void image_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceImage *simg = (SpaceImage *)slink; + + if (!ELEM(GS(old_id->name), ID_IM, ID_GD, ID_MSK)) { + return; + } + + if ((ID *)simg->image == old_id) { + simg->image = (Image *)new_id; + id_us_ensure_real(new_id); + } + + if ((ID *)simg->gpd == old_id) { + simg->gpd = (bGPdata *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + + if ((ID *)simg->mask_info.mask == old_id) { + simg->mask_info.mask = (Mask *)new_id; + id_us_ensure_real(new_id); + } +} + /**************************** spacetype *****************************/ /* only called once, from space/spacetypes.c */ @@ -1002,7 +1029,8 @@ void ED_spacetype_image(void) st->refresh = image_refresh; st->listener = image_listener; st->context = image_context; - + st->id_remap = image_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype image region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c index 243a522011b..69966e9bf34 100644 --- a/source/blender/editors/space_logic/space_logic.c +++ b/source/blender/editors/space_logic/space_logic.c @@ -38,7 +38,10 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "DNA_gpencil_types.h" + #include "BKE_context.h" +#include "BKE_library.h" #include "BKE_screen.h" #include "ED_space_api.h" @@ -300,6 +303,21 @@ static void logic_header_region_draw(const bContext *C, ARegion *ar) /**************************** spacetype *****************************/ +static void logic_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceLogic *slog = (SpaceLogic *)slink; + + if (!ELEM(GS(old_id->name), ID_GD)) { + return; + } + + if ((ID *)slog->gpd == old_id) { + slog->gpd = (bGPdata *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_logic(void) { @@ -317,7 +335,8 @@ void ED_spacetype_logic(void) st->keymap = logic_keymap; st->refresh = logic_refresh; st->context = logic_context; - + st->id_remap = logic_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype logic region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index e2b36c5b5ae..3b5604087b9 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -33,6 +33,7 @@ #include <stdio.h> #include "DNA_anim_types.h" +#include "DNA_group_types.h" #include "DNA_scene_types.h" #include "MEM_guardedalloc.h" @@ -501,6 +502,19 @@ static void nla_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn) } } +static void nla_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceNla *snla = (SpaceNla *)slink; + + if (!ELEM(GS(old_id->name), ID_GR)) { + return; + } + + if ((ID *)snla->ads->filter_grp == old_id) { + snla->ads->filter_grp = (Group *)new_id; + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_nla(void) { @@ -517,7 +531,8 @@ void ED_spacetype_nla(void) st->operatortypes = nla_operatortypes; st->listener = nla_listener; st->keymap = nla_keymap; - + st->id_remap = nla_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype nla region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 6ae72e2a164..ffe510016ff 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -740,34 +740,6 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) } } -void ED_node_id_unref(SpaceNode *snode, const ID *id) -{ - if (GS(id->name) == ID_SCE) { - if (snode->id == id) { - /* nasty DNA logic for SpaceNode: - * ideally should be handled by editor code, but would be bad level call - */ - bNodeTreePath *path, *path_next; - for (path = snode->treepath.first; path; path = path_next) { - path_next = path->next; - MEM_freeN(path); - } - BLI_listbase_clear(&snode->treepath); - - snode->id = NULL; - snode->from = NULL; - snode->nodetree = NULL; - snode->edittree = NULL; - } - } - else if (GS(id->name) == ID_OB) { - if (snode->from == id) { - snode->flag &= ~SNODE_PIN; - snode->from = NULL; - } - } -} - void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree)) { /* XXX This does not work due to layout functions relying on node->block, diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index df484724fc5..4ef703c8994 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -28,6 +28,7 @@ * \ingroup spnode */ +#include "DNA_gpencil_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" @@ -821,6 +822,41 @@ static int node_context(const bContext *C, const char *member, bContextDataResul return 0; } +static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceNode *snode = (SpaceNode *)slink; + + if (GS(old_id->name) == ID_SCE) { + if (snode->id == old_id) { + /* nasty DNA logic for SpaceNode: + * ideally should be handled by editor code, but would be bad level call + */ + BLI_freelistN(&snode->treepath); + + /* XXX Untested in case new_id != NULL... */ + snode->id = new_id; + snode->from = NULL; + snode->nodetree = NULL; + snode->edittree = NULL; + } + } + else if (GS(old_id->name) == ID_OB) { + if (snode->from == old_id) { + if (new_id == NULL) { + snode->flag &= ~SNODE_PIN; + } + snode->from = new_id; + } + } + else if (GS(old_id->name) == ID_GD) { + if ((ID *)snode->gpd == old_id) { + snode->gpd = (bGPdata *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_node(void) { @@ -840,6 +876,7 @@ void ED_spacetype_node(void) st->refresh = node_area_refresh; st->context = node_context; st->dropboxes = node_dropboxes; + st->id_remap = node_id_remap; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 554009da8be..43e9c262172 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -502,6 +502,11 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) BKE_reportf(CTX_wm_reports(C), RPT_ERROR, "Library path '%s' does not exist, correct this before saving", expanded); } + else if (lib->id.tag & LIB_TAG_MISSING) { + BKE_reportf(CTX_wm_reports(C), RPT_INFO, + "Library path '%s' is now valid, please reload the library", expanded); + lib->id.tag &= ~LIB_TAG_MISSING; + } } } else { diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 2627b978b40..8cee696b2ac 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -2079,36 +2079,3 @@ void OUTLINER_OT_group_link(wmOperatorType *ot) /* properties */ RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object"); } - -/******** Utils to clear any ref to freed ID... **********/ - -void ED_outliner_id_unref(SpaceOops *so, const ID *id) -{ - /* Some early out checks. */ - if (!TREESTORE_ID_TYPE(id)) { - return; /* ID type is not used by outilner... */ - } - - if (so->search_tse.id == id) { - so->search_tse.id = NULL; - } - - if (so->treestore) { - TreeStoreElem *tselem; - BLI_mempool_iter iter; - bool changed = false; - - BLI_mempool_iternew(so->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - if (tselem->id == id) { - tselem->id = NULL; - changed = true; - } - } - if (so->treehash && changed) { - /* rebuild hash table, because it depends on ids too */ - /* postpone a full rebuild because this can be called many times on-free */ - so->storeflag |= SO_TREESTORE_REBUILD; - } - } -} diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index dc81be7a8e0..2e46ffa6437 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -230,6 +230,7 @@ void OUTLINER_OT_object_operation(struct wmOperatorType *ot); void OUTLINER_OT_group_operation(struct wmOperatorType *ot); void OUTLINER_OT_lib_operation(struct wmOperatorType *ot); void OUTLINER_OT_id_operation(struct wmOperatorType *ot); +void OUTLINER_OT_id_remap(struct wmOperatorType *ot); void OUTLINER_OT_data_operation(struct wmOperatorType *ot); void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot); void OUTLINER_OT_action_set(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 83677b6bd86..2a210e382a2 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -57,6 +57,7 @@ #include "BKE_fcurve.h" #include "BKE_group.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -230,7 +231,8 @@ static void unlink_group_cb( } else { Main *bmain = CTX_data_main(C); - BKE_group_unlink(bmain, group); + BKE_libblock_unlink(bmain, group, false); + BKE_libblock_free(bmain, group); } } @@ -246,7 +248,7 @@ static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEleme } static void outliner_do_libdata_operation( - bContext *C, Scene *scene, SpaceOops *soops, ListBase *lb, + bContext *C, Scene *scene, SpaceOops *soops, ListBase *lb, void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *), void *user_data) { @@ -522,8 +524,7 @@ static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te) */ void outliner_do_object_operation_ex( bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb, - void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, - TreeStoreElem *, TreeStoreElem *, void *), + void (*operation_cb)(bContext *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *), bool select_recurse) { TreeElement *te; @@ -565,7 +566,7 @@ void outliner_do_object_operation( static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), TreeStoreElem *tselem, void *UNUSED(arg)) { - BKE_animdata_free(tselem->id); + BKE_animdata_free(tselem->id, true); } diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 1dd66366e5d..76bf9c701ed 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -486,6 +486,39 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl) return (SpaceLink *)soutlinern; } +static void outliner_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceOops *so = (SpaceOops *)slink; + + /* Some early out checks. */ + if (!TREESTORE_ID_TYPE(old_id)) { + return; /* ID type is not used by outilner... */ + } + + if (so->search_tse.id == old_id) { + so->search_tse.id = new_id; + } + + if (so->treestore) { + TreeStoreElem *tselem; + BLI_mempool_iter iter; + bool changed = false; + + BLI_mempool_iternew(so->treestore, &iter); + while ((tselem = BLI_mempool_iterstep(&iter))) { + if (tselem->id == old_id) { + tselem->id = new_id; + changed = true; + } + } + if (so->treehash && changed) { + /* rebuild hash table, because it depends on ids too */ + /* postpone a full rebuild because this can be called many times on-free */ + so->storeflag |= SO_TREESTORE_REBUILD; + } + } +} + /* only called once, from space_api/spacetypes.c */ void ED_spacetype_outliner(void) { @@ -502,7 +535,8 @@ void ED_spacetype_outliner(void) st->operatortypes = outliner_operatortypes; st->keymap = outliner_keymap; st->dropboxes = outliner_dropboxes; - + st->id_remap = outliner_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index fce40f8ca59..a2a80297041 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -32,6 +32,7 @@ #include <string.h> #include <stdio.h> +#include "DNA_gpencil_types.h" #include "DNA_scene_types.h" #include "DNA_mask_types.h" @@ -41,6 +42,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_library.h" #include "BKE_screen.h" #include "BKE_sequencer.h" #include "BKE_global.h" @@ -687,6 +689,22 @@ static void sequencer_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUS break; } } + +static void sequencer_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceSeq *sseq = (SpaceSeq *)slink; + + if (!ELEM(GS(old_id->name), ID_GD)) { + return; + } + + if ((ID *)sseq->gpd == old_id) { + sseq->gpd = (bGPdata *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } +} + /* ************************************* */ /* only called once, from space/spacetypes.c */ @@ -708,6 +726,7 @@ void ED_spacetype_sequencer(void) st->dropboxes = sequencer_dropboxes; st->refresh = sequencer_refresh; st->listener = sequencer_listener; + st->id_remap = sequencer_id_remap; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index 0a6a9a81e63..0dea59fd68c 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -38,6 +38,7 @@ #include "BLI_blenlib.h" #include "BKE_context.h" +#include "BKE_library.h" #include "BKE_screen.h" #include "BKE_text.h" @@ -562,6 +563,20 @@ static void text_properties_region_draw(const bContext *C, ARegion *ar) } } +static void text_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceText *stext = (SpaceText *)slink; + + if (!ELEM(GS(old_id->name), ID_GD)) { + return; + } + + if ((ID *)stext->text == old_id) { + stext->text = (Text *)new_id; + id_us_ensure_real(new_id); + } +} + /********************* registration ********************/ /* only called once, from space/spacetypes.c */ @@ -582,7 +597,8 @@ void ED_spacetype_text(void) st->listener = text_listener; st->context = text_context; st->dropboxes = text_dropboxes; - + st->id_remap = text_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype text region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index fa14ca96fe2..96dda65b81d 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1400,6 +1400,66 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes return -1; /* found but not available */ } +static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_id) +{ + View3D *v3d; + ARegion *ar; + bool is_local = false; + + if (!ELEM(GS(old_id->name), ID_OB, ID_MA, ID_IM, ID_MC)) { + return; + } + + for (v3d = (View3D *)slink; v3d; v3d = v3d->localvd, is_local = true) { + if ((ID *)v3d->camera == old_id) { + v3d->camera = (Object *)new_id; + if (!new_id) { + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = is_local ? ((RegionView3D *)ar->regiondata)->localvd : ar->regiondata; + if (rv3d && (rv3d->persp == RV3D_CAMOB)) { + rv3d->persp = RV3D_PERSP; + } + } + } + } + } + if ((ID *)v3d->ob_centre == old_id) { + v3d->ob_centre = (Object *)new_id; + if (new_id == NULL) { /* Otherwise, bonename may remain valid... We could be smart and check this, too? */ + v3d->ob_centre_bone[0] = '\0'; + } + } + + if ((ID *)v3d->defmaterial == old_id) { + v3d->defmaterial = (Material *)new_id; + } +#if 0 /* XXX Deprecated? */ + if ((ID *)v3d->gpd == old_id) { + v3d->gpd = (bGPData *)new_id; + } +#endif + + if (ELEM(GS(old_id->name), ID_IM, ID_MC)) { + for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { + if ((ID *)bgpic->ima == old_id) { + bgpic->ima = (Image *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + if ((ID *)bgpic->clip == old_id) { + bgpic->clip = (MovieClip *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + } + } + + if (is_local) { + break; + } + } +} /* only called once, from space/spacetypes.c */ void ED_spacetype_view3d(void) @@ -1419,7 +1479,8 @@ void ED_spacetype_view3d(void) st->keymap = view3d_keymap; st->dropboxes = view3d_dropboxes; st->context = view3d_context; - + st->id_remap = view3d_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype view3d main region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 1f4ce926f16..e2f60955c81 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -57,6 +57,7 @@ #include "BKE_multires.h" #include "BKE_packedFile.h" #include "BKE_paint.h" +#include "BKE_screen.h" #include "ED_armature.h" #include "ED_buttons.h" @@ -326,22 +327,14 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *ar, void *arg_info /** * Use to free ID references within runtime data (stored outside of DNA) * - * \note Typically notifiers take care of this, - * but there are times we have to free references immediately, see: T44376 + * \param new_id may be NULL to unlink \a old_id. */ -void ED_spacedata_id_unref(struct SpaceLink *sl, const ID *id) +void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id) { + SpaceType *st = BKE_spacetype_from_id(sl->spacetype); - switch (sl->spacetype) { - case SPACE_OUTLINER: - ED_outliner_id_unref((SpaceOops *)sl, id); - break; - case SPACE_BUTS: - ED_buttons_id_unref((SpaceButs *)sl, id); - break; - case SPACE_NODE: - ED_node_id_unref((SpaceNode *)sl, id); - break; + if (st && st->id_remap) { + st->id_remap(sa, sl, old_id, new_id); } } diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 63ea836e3de..de793054ca7 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -342,7 +342,7 @@ static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain) static void rna_ID_animation_data_free(ID *id, Main *bmain) { - BKE_animdata_free(id); + BKE_animdata_free(id, true); DAG_relations_tag_update(bmain); } diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 4b7ce640a56..679f20fab83 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -58,6 +58,7 @@ #include "BKE_armature.h" #include "BKE_lamp.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_object.h" #include "BKE_material.h" #include "BKE_icons.h" @@ -160,7 +161,8 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports } - BKE_scene_unlink(bmain, scene, scene_new); + BKE_libblock_remap(bmain, scene, scene_new, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); + BKE_libblock_free(bmain, scene); RNA_POINTER_INVALIDATE(scene_ptr); } else { @@ -226,7 +228,7 @@ static void rna_Main_objects_remove(Main *bmain, ReportList *reports, PointerRNA { Object *object = object_ptr->data; if (ID_REAL_USERS(object) <= 0) { - BKE_object_unlink(bmain, object); /* needed or ID pointers to this are not cleared */ + BKE_libblock_unlink(bmain, object, false); BKE_libblock_free(bmain, object); RNA_POINTER_INVALIDATE(object_ptr); } @@ -542,7 +544,7 @@ static Group *rna_Main_groups_new(Main *bmain, const char *name) static void rna_Main_groups_remove(Main *bmain, PointerRNA *group_ptr) { Group *group = group_ptr->data; - BKE_group_unlink(bmain, group); + BKE_libblock_unlink(bmain, group, false); BKE_libblock_free(bmain, group); RNA_POINTER_INVALIDATE(group_ptr); } @@ -736,7 +738,6 @@ static Mask *rna_Main_mask_new(Main *bmain, const char *name) static void rna_Main_masks_remove(Main *bmain, PointerRNA *mask_ptr) { Mask *mask = mask_ptr->data; - BKE_mask_free(bmain, mask); BKE_libblock_free(bmain, mask); RNA_POINTER_INVALIDATE(mask_ptr); } diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 5b65a2bbfd4..8523b7275bf 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -488,7 +488,7 @@ void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat, short compatibili ntreeExecGPUNodes(exec, mat, 1, compatibility); ntreeShaderEndExecTree(exec); - ntreeFreeTree_ex(localtree, false); + ntreeFreeTree(localtree); MEM_freeN(localtree); } diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index c88e3b36e27..4d711f86644 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -66,6 +66,7 @@ #include "BKE_global.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_node.h" @@ -2267,7 +2268,8 @@ static void free_all_freestyle_renders(void) if (freestyle_render) { freestyle_scene = freestyle_render->scene; RE_FreeRender(freestyle_render); - BKE_scene_unlink(re1->freestyle_bmain, freestyle_scene, NULL); + BKE_libblock_unlink(re1->freestyle_bmain, freestyle_scene, false); + BKE_libblock_free(re1->freestyle_bmain, freestyle_scene); } } BLI_freelistN(&re1->freestyle_renders); diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index 8f61f4159e6..530ebc084be 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -3806,6 +3806,7 @@ void RE_sample_material_free(Material *mat) MTex *mtex= mat->mtex[tex_nr]; if (mtex->tex) { + /* don't update user counts as we are freeing a duplicate */ BKE_texture_free(mtex->tex); MEM_freeN(mtex->tex); mtex->tex = NULL; @@ -3814,7 +3815,7 @@ void RE_sample_material_free(Material *mat) } /* don't update user counts as we are freeing a duplicate */ - BKE_material_free_ex(mat, false); + BKE_material_free(mat); MEM_freeN(mat); } diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 388837af67a..9bb2462a4e9 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -191,7 +191,7 @@ void WM_ndof_deadzone_set(float deadzone); void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference); void WM_main_add_notifier(unsigned int type, void *reference); void WM_main_remove_notifier_reference(const void *reference); -void WM_main_remove_editor_id_reference(const struct ID *id); +void WM_main_remap_editor_id_reference(struct ID *old_id, struct ID *new_id); /* reports */ void WM_report_banner_show(void); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index f632dd9aff4..4515ae92f66 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -241,7 +241,7 @@ void WM_main_remove_notifier_reference(const void *reference) } } -void WM_main_remove_editor_id_reference(const ID *id) +void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id) { Main *bmain = G.main; bScreen *sc; @@ -253,7 +253,7 @@ void WM_main_remove_editor_id_reference(const ID *id) SpaceLink *sl; for (sl = sa->spacedata.first; sl; sl = sl->next) { - ED_spacedata_id_unref(sl, id); + ED_spacedata_id_remap(sa, sl, old_id, new_id); } } } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 917e2bf5913..a1ca89c6a8c 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -61,6 +61,7 @@ #include "BKE_global.h" #include "BKE_icons.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_mball_tessellate.h" #include "BKE_node.h" @@ -160,9 +161,9 @@ void WM_init(bContext *C, int argc, const char **argv) BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */ BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */ - BKE_library_callback_free_editor_id_reference_set(WM_main_remove_editor_id_reference); /* library.c */ + BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */ BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */ - BKE_spacedata_callback_id_unref_set(ED_spacedata_id_unref); /* screen.c */ + BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */ DAG_editors_update_cb(ED_render_id_flush_update, ED_render_scene_update, ED_render_scene_update_pre); /* depsgraph.c */ diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index 30ad5b37777..0ea3a3e62eb 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -74,6 +74,7 @@ extern "C" #include "BKE_node.h" #include "BKE_report.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_modifier.h" #include "BKE_material.h" #include "BKE_text.h" |