ID-Remap - Step one: core work (cleanup and rework of generic ID datablock handling).
authorBastien Montagne <montagne29@wanadoo.fr>
Wed, 22 Jun 2016 15:29:38 +0000 (17:29 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Wed, 22 Jun 2016 15:53:50 +0000 (17:53 +0200)
This commit changes a lot of how IDs are handled internally, especially the unlinking/freeing
processes. So far, this was very fuzy, to summarize cleanly deleting or replacing a datablock
was pretty much impossible, except for a few special cases.

Also, unlinking was handled by each datatype, in a rather messy and prone-to-errors way (quite
a few ID usages were missed or wrongly handled that way).

One of the main goal of id-remap branch was to cleanup this, and fatorize ID links handling
by using library_query utils to allow generic handling of those, which is now the case
(now, generic ID links handling is only "knwon" from readfile.c and library_query.c).

This commit also adds backends to allow live replacement and deletion of datablocks in Blender
(so-called 'remapping' process, where we replace all usages of a given ID pointer by a new one,
or NULL one in case of unlinking).

This will allow nice new features, like ability to easily reload or relocate libraries, real immediate
deletion of datablocks in blender, replacement of one datablock by another, etc.
Some of those are for next commits.

A word of warning: this commit is highly risky, because it affects potentially a lot in Blender core.
Though it was tested rather deeply, being totally impossible to check all possible ID usage cases,
it's likely there are some remaining issues and bugs in new code... Please report them! ;)

Review task: D2027 (https://developer.blender.org/D2027).
Reviewed by campbellbarton, thanks a bunch.

95 files changed:
source/blender/blenkernel/BKE_animsys.h
source/blender/blenkernel/BKE_curve.h
source/blender/blenkernel/BKE_group.h
source/blender/blenkernel/BKE_library.h
source/blender/blenkernel/BKE_library_query.h
source/blender/blenkernel/BKE_library_remap.h [new file with mode: 0644]
source/blender/blenkernel/BKE_linestyle.h
source/blender/blenkernel/BKE_mask.h
source/blender/blenkernel/BKE_mball.h
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/BKE_object.h
source/blender/blenkernel/BKE_sca.h
source/blender/blenkernel/BKE_scene.h
source/blender/blenkernel/BKE_screen.h
source/blender/blenkernel/BKE_sound.h
source/blender/blenkernel/BKE_world.h
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/action.c
source/blender/blenkernel/intern/anim_sys.c
source/blender/blenkernel/intern/armature.c
source/blender/blenkernel/intern/brush.c
source/blender/blenkernel/intern/camera.c
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/effect.c
source/blender/blenkernel/intern/font.c
source/blender/blenkernel/intern/gpencil.c
source/blender/blenkernel/intern/group.c
source/blender/blenkernel/intern/image.c
source/blender/blenkernel/intern/key.c
source/blender/blenkernel/intern/lamp.c
source/blender/blenkernel/intern/lattice.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/library_query.c
source/blender/blenkernel/intern/library_remap.c [new file with mode: 0644]
source/blender/blenkernel/intern/linestyle.c
source/blender/blenkernel/intern/mask.c
source/blender/blenkernel/intern/material.c
source/blender/blenkernel/intern/mball.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenkernel/intern/movieclip.c
source/blender/blenkernel/intern/node.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/paint.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/sca.c
source/blender/blenkernel/intern/scene.c
source/blender/blenkernel/intern/screen.c
source/blender/blenkernel/intern/sequencer.c
source/blender/blenkernel/intern/sound.c
source/blender/blenkernel/intern/speaker.c
source/blender/blenkernel/intern/text.c
source/blender/blenkernel/intern/texture.c
source/blender/blenkernel/intern/world.c
source/blender/compositor/operations/COM_MaskOperation.cpp
source/blender/editors/animation/anim_channels_edit.c
source/blender/editors/include/ED_buttons.h
source/blender/editors/include/ED_node.h
source/blender/editors/include/ED_outliner.h
source/blender/editors/include/ED_util.h
source/blender/editors/include/ED_view3d.h
source/blender/editors/mesh/editmesh_undo.c
source/blender/editors/object/object_add.c
source/blender/editors/object/object_group.c
source/blender/editors/render/render_preview.c
source/blender/editors/screen/screen_edit.c
source/blender/editors/sound/sound_ops.c
source/blender/editors/space_action/space_action.c
source/blender/editors/space_buttons/buttons_context.c
source/blender/editors/space_buttons/space_buttons.c
source/blender/editors/space_clip/space_clip.c
source/blender/editors/space_graph/space_graph.c
source/blender/editors/space_image/space_image.c
source/blender/editors/space_logic/space_logic.c
source/blender/editors/space_nla/space_nla.c
source/blender/editors/space_node/node_edit.c
source/blender/editors/space_node/space_node.c
source/blender/editors/space_outliner/outliner_draw.c
source/blender/editors/space_outliner/outliner_edit.c
source/blender/editors/space_outliner/outliner_intern.h
source/blender/editors/space_outliner/outliner_tools.c
source/blender/editors/space_outliner/space_outliner.c
source/blender/editors/space_sequencer/space_sequencer.c
source/blender/editors/space_text/space_text.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/util/ed_util.c
source/blender/makesrna/intern/rna_ID.c
source/blender/makesrna/intern/rna_main_api.c
source/blender/nodes/shader/node_shader_tree.c
source/blender/render/intern/source/pipeline.c
source/blender/render/intern/source/render_texture.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_init_exit.c
source/gameengine/GamePlayer/ghost/GPG_ghost.cpp

index 6524afff051e49bd7eb9374d95735dcc0cb5629f..772e08589c16f8116999afbe6afd8311e00d1ba3 100644 (file)
@@ -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);
index 061270b8b4127aaaa150f6da3b779604d05d0d73..23b3128f328915f9977e3f2a43c4f6f56449dffa 100644 (file)
@@ -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);
index 9056e48cf50d2d4beca03b85152303e6ab1dcd7c..ae6e52b613b247777e1461404398b0c2863965cf 100644 (file)
@@ -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);
index 2215fbfbd7db31f5c1b3d5777539128ead4a4e13..56f040ab26045d10b84ce223c658d9444bb48464 100644 (file)
@@ -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")
index 2e73be576f981ee4a5f609b2fa8703ed4d176d1c..c89dce99caae1a5ec4e31527b8916235ad6bb8bd 100644 (file)
@@ -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 (file)
index 0000000..e85a3e6
--- /dev/null
@@ -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
index e3eead4102c801251a8944dda6c30a9985e0cfad..e343cd29622bb6ccf1e78357c5f8c285186cad3c 100644 (file)
@@ -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);
index 25893d54dcab79e47b18808133bb1d081bbd0008..f3d12b5a8cc51948fca24d295edca4e1b557aa9a 100644 (file)
@@ -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]);
index 0574b88bef3bedbe9f0268066da247ad505d4dfd..b8258455c658507af7d3231d883f4afd93f03028 100644 (file)
@@ -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);
index d8d869015a3da6a238c46bcccc24a4dbd5a27b84..9330f41d19a205cb50c8fd97ac2449866e3820c7 100644 (file)
@@ -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);
index 4b92c1f7a3ad4e097aa79181246412d34719dce9..bf198c9b86b50608f9d189c3c51b5c2ebf275400 100644 (file)
@@ -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);
index c591ec2a0aaaf3974124379943932e7b6ee67692..f46fb73f4c9b16887c7232b06c984b8d10937d6d 100644 (file)
@@ -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);
index fa448aa97b8be2a5499aeb365304ea693d7cd3e0..1743a4431fd93cc9416ce7d1bcac89186a1389c4 100644 (file)
@@ -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);
index 12bfc07e95817d3ba8e6e006185f7239f99e7c43..ccb7dc8e015549b21d948f086d7104819e6b7a76 100644 (file)
@@ -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);
index d05df3470b5af3cc4dfbf81d0d294b5b6694c0ba..14e978b23f239c4446c88a193b246237aa2283bf 100644 (file)
@@ -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);
index 67db2537c8fbd81902eacafc706deac8922d3eb5..18d9fe061a88f06955fdb9c2798608127dab79f4 100644 (file)
@@ -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);
index 8d7ab2309198d3de8dfc722b4fbe46b4500034fb..0be61fe022983670b8a824084b6f8a7c3bad6655 100644 (file)
@@ -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);
index 862642248513627f2a64bcee751da5aa5be50d72..6af9f8a71ee643a6c2740f1cbdb6dd680ed8c936 100644 (file)
@@ -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
index df9b9683687dd6b69874f6e79e70702b1230a19c..46ee8a4d888aa3a6e038efbbbabcfa180165a7f7 100644 (file)
@@ -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);
 }
 
 /* .................................. */
index 99aae6239e8679388b1c43d185976551bb556f40..91b33f3efd3d1b6fc47d7d783c870b6aab241e5e 100644 (file)
@@ -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) {
index 04b4733fd440d781a1699bb53eddaadf27dad862..038993777cfdef0146f03a92aa0aedb68863e95f 100644 (file)
@@ -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;
        }
 }
 
index da7863096e3df1a78ae475fc988cf17424ca38e2..a3e006a162f0fdb6cd6ce78a718b11d30b172391 100644 (file)
@@ -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));
 }
 
 /**
index 96bac2c2f41e3f2ff96d1bc3ea7127b39c34b936..eabee742327e602f55c478c7e04f502401946dbf 100644 (file)
@@ -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 *******************************/
index 8afb451f768d3e8fb04dc9451bbede657cd936ff..dec6ff22360794bc76e39b2384b19f6a3a2cd0b5 100644 (file)
@@ -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)
index f06dd6f9de47b86ee9b45815fa7513fecaac54b7..a8268c03d95b152209b42930f9be7fb2a44c7a98 100644 (file)
@@ -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);
 
index 812d1c669234280ba5ef76746d1f78852ae1747e..5e1f8814ed6366fb70301897c4b07649efd914bf 100644 (file)
@@ -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) {
index f3eb5430bce066b6c29ed648688168cfc119d32f..af1bcd0c5457e60d1495c4c23e22b85d5345505b 100644 (file)
@@ -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 ---------- */
index a44eb1df9fe0b0a1724e47ba0626df5458b97baf..4fdee7e36333e1906e085df377a8d9d12a769ec0 100644 (file)
@@ -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)
index 0b2c844cb2c2b6e37ae5c8bfce2d66917b60f871..14a445649ad663cbdd91a470647c5541e028fda2 100644 (file)
@@ -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 */
index 362f41335d24e52031f0f1993ab60437112a86cd..2517e2cc197637a677ffca542b9d221f0c837eb7 100644 (file)
 #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)
index 49a573489effc12d1eb9ee2412efc28403f7d31e..692b703f721edf23e5e3848413840aa2354d2171 100644 (file)
@@ -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);
 
index b350e93228132e6f0bfae968a304408c5d828538..58c0a5671165ad10aea4d569bc59c4e88ea07c3a 100644 (file)
@@ -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(&lt->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(&lt->id);
-               lt->adt = NULL;
+               lt->editlatt = NULL;
        }
 }
 
index 961b45df4e631c9e1c3a8943dcff37d5748da875..fe16df18813596cd061bfe55a60ae8b36f585e08 100644 (file)
@@ -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"
 #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"
 #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");
index 4fe408e755a5b9ca075b491312e3ef8e7a917e4e..be3dde2753a9c857cf64826ce3854f1262eb0ae9 100644 (file)
@@ -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 (file)
index 0000000..4bde075
--- /dev/null
@@ -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);
+                       }
+               }
+       }
+}
index 5a1dfc0404592d1e6d0a1678e6391e907b963b33..30dc48819e92c0510c893edbb054aeccf8b4b6c6 100644 (file)
@@ -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) {
index 930a3c487ecc9205d5d0155361f7d49b663ebc49..94e53755ac447e403b3305b12975d73b04b3e115 100644 (file)
@@ -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);
index 30f82a50ed96e1ac040793a16f3fc1593df11ba6..db5ac54ada906016ca86f5d733cfff8f2c380f4d 100644 (file)
@@ -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;
        }
index d7019aa845820df405b2b84e3a88ea6111885423..685cd35fc20664288e8d64cefc2752bfd9264eb8 100644 (file)
 
 /* 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);
 }
index 2af78cca79f6cb4e16602c60000cfda8356c1b45..4e47dfcce745ee7ade7292217f4e834d1b9c60bf 100644 (file)
@@ -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)
index d2bfcfb08877db5dffbe5cec8467ac1596379758..5f667732b04f7a61b65f98c6fda8a5a2b5abc01f 100644 (file)
@@ -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);
index 2b381f6ff0b00370ce9dd4af35ba3e7d2530e132..d78ddc41e9770aefa686bf4991d7267cdbde4ae4 100644 (file)
@@ -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);
        }
 }
index 65ee153e00b92abb0fcec499be9ed8de9fed606f..d4ba70ee0a613917e4e1aee8f067097f13ccc8f9 100644 (file)
@@ -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)
 {
index 3a2663c5d487608b82720c65ea5a770e208761f3..8c1502643c527b10b05798ab80c38277af87d413 100644 (file)
@@ -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);
 }
 
index 25dd7fff380ebd26b8c4a147d076316eda22db58..633227d68f3491257ba79ad4fd7fa4743ddaab00 100644 (file)
@@ -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;
index e90a39e8c0e9b3c0e71d2e9fd19c06d9c75ef7a0..a468420f87dd44f9e5da6864d373f155c697c811 100644 (file)
@@ -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)
 {
index a3393b6b9c0692ae56742b6762128a9a5c4bc99d..0e8efca04d0874d02d0874e244efc3ed8dfd45ba 100644 (file)
@@ -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)
index 139c6670f74b3efb92570896033085ac9c81dc34..857bd5447c8546afe3aeab182bcc6016316bc079 100644 (file)
@@ -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);
index c82f3a3af2360625a029fa36a4f3a027e1a8442b..5ef502e0182c5a1ed3aa76be27a052a490a8b442 100644 (file)
@@ -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");
index b016f8a49ed5ac2e5d08b59385450b5e6d534e1d..414be73e23409cd1b20b30c8c9f0a20979c78e1b 100644 (file)
@@ -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;
index c452065fbadba066c607e95d00565a7bfc910760..e5075a2d3828190ef44fac260dd3805eb0f22f0d 100644 (file)
@@ -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);
 }
index 6def9e3e5035be593526897d52ff4bd7bc8c270f..594f9dffbee440c9a922c7f83b35d657fa10d6cf 100644 (file)
@@ -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
 }
 
index d353042b7115518d34a42d6a2e9299d3ce01087d..9326ece7a4b2336b3a69a3a750b51092680bb949 100644 (file)
@@ -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);
 }
 
 /* ------------------------------------------------------------------------- */
index 17a2e7f14fd10e20e5d5562a85ffe088f7c648e9..ec021586be5dfafd5e814cc84b11b2233e8d9d83 100644 (file)
 
 #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)
index 220b4e908a613cf6bfae17a70087e055345a53fe..d6e5fdf86bb96ebbbc7abdb81882a9b93b02b287 100644 (file)
@@ -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);
                }
        }
index 8822c8511de6a4ea4d5a8666646ffce1155ea418..c98470fb194c304d2e31a098b3020cd9e6ef0ab3 100644 (file)
@@ -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);
                }
        }
        
index 9a987d7618c4f0c048a97fa05171278c92659bbd..64c16605dec6f372cc0bff87e3aecd77e51ec264 100644 (file)
@@ -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__ */
index 7fe9a0c320c32f06cdf8139ec935b61c992f0f3a..f7b9d6b4f9e483b08b28eb2a8b3aefa90f7faafe 100644 (file)
@@ -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);
 
index af4af8e2f5d7b0ac3e72ed2221079aa8e4a43699..73ee254224737b33fd5645fce96e17bd3bf161b5 100644 (file)
 #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__ */
index f143ea478c65f26b20300d47f2843f64cb67bcce..b6b80b93e0bf269264cdb2e48b97b8cc2850c662 100644 (file)
@@ -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);
 
index c23c2eed890c48f04e5f4a1975db8805e2f986ac..baab6b6100de1f13ca0317dcc355248cdb8b6007 100644 (file)
@@ -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__ */
index 8b16b2a977e7d73c342e1d12b59f3b87531da7bc..62656d75b9acef935c7ff31ea1109fea86d8f198 100644 (file)
@@ -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);
 }
 
index 09c9442db54dd8c565c54277d52e4505aa883b6d..f85c76291cda6ca013890642e846bb1d79307f0b 100644 (file)
@@ -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) {
index 76a8a68c42dab77bd184e8d566902bc78d68dfbd..2b87a890f0f8b684ad59e5a1b2f7e231f6870a20 100644 (file)
@@ -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);
 
index f4260a0cd338ffc4fc48a410753c7be59f1c9edf..132c3fa5438b9bf8fcefc598dbd55c3f115b3eef 100644 (file)
@@ -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);
index a459f982ada31fed1202b79a178798079a592485..62aeca4b9d121c62774d606d671e3f17feea3752 100644 (file)
@@ -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;
 }
index a4d9a920cbbe86932a7c146efe6ed9727b6b32b2..4931426d62e0e1150beba064483e59690df22942 100644 (file)
@@ -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;
index 60240109432ff1214c85d3932ed5d78ee26b442a..671d6bb083e113dd2c76e14885e0bb40347afdde 100644 (file)
@@ -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;
index 42e2d6b90f04894d83af0c4b59c8643cde7c299f..5b03bdd776178bf2383c20c8e522daf06699f775 100644 (file)
@@ -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;
-               }
-       }
-}
index 126a27c36cb0ddcf50d13c0fbab36fcf33bc6800..e4c23ad74f8ce11b2835ce57182d88e05843e606 100644 (file)
@@ -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;
index e1d4e4fabc561d7ae235c58861801e948cf90a06..415839ab761b3999e9a776d461cab19f2dabba86 100644 (file)
@@ -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");
index c6a8a9753d13a5430e39f0a0761c746a5ce535d8..a7284694f6407b33bad35edcb72474be66dfef54 100644 (file)
@@ -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;
index 168f9c0dfdf1f845b3eedefd118d6e8fefaa8996..35a658eac236f0eb51ee61f29111294646ba3bae 100644 (file)
@@ -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;
index 243a522011b13e48cd0736bbc0096713ca003ccc..69966e9bf346ed3e26c9cdc509abfe2e127145ec 100644 (file)
 #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;
index e2b36c5b5ae7632f306a83ab4fd169470956eba7..3b5604087b9f2bd29617799277682313a8f6a5e5 100644 (file)
@@ -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;
index 6ae72e2a1648af4f5213fa7daed104e551c67f7a..ffe510016ff2486b23597c825897abf2319bd7c4 100644 (file)
@@ -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,
index df484724fc5b5dcac70f064cca2176332837c917..4ef703c899414ff8c65473ad6ce898a1a0e772b1 100644 (file)
@@ -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");
index 554009da8be5ef1d9f96f22cbf3c5d742c82f2c7..43e9c262172edb51c67416eb3bdd219f5c1ca593 100644 (file)
@@ -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 {
index 2627b978b40d6605fb53ef062cec64680c38fd21..8cee696b2acf92f1c39635f5acf3ef9b45f0a32f 100644 (file)
@@ -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;
-               }
-       }
-}
index dc81be7a8e0bdc6adfa8a4a052e7573a1688cf21..2e46ffa643771cdc5c65862f0091f267153f7ce6 100644 (file)
@@ -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);
index 83677b6bd8636c89534f48a5db53ea672f664e86..2a210e382a25a932d37020b53b08efbea69ee294 100644 (file)
@@ -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);
 }
 
 
index 1dd66366e5df9b9f3e6101bdd3ed8c89d2aac7fe..76bf9c701ed433675b2003b9c482342cf27210e1 100644 (file)
@@ -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;
index fce40f8ca59ed5452a129642168c8936a2c599b9..a2a80297041fc90603a38ee156fb1be01a321be9 100644 (file)
@@ -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");
index 0a6a9a81e63fa1fb43ce99ba4f7a02f96768cedb..0dea59fd68caa61db05fd118ac7639cd090ca557 100644 (file)
@@ -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;
index fa14ca96fe2cca6b9a599298c6622edded1fa23d..96dda65b81db0906c0a1eb847ca3a65e2676fbe5 100644 (file)
@@ -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;
index 1f4ce926f168e77a2cb25b7dbb3c31ac67a61dca..e2f60955c81c18acff6582a4f4981facb45fc7e6 100644 (file)
@@ -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);
        }
 }
 
index 63ea836e3de6a60012f5490a9001e84e2225b319..de793054ca7e25938dc074d9f1076e44ea68790e 100644 (file)
@@ -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);
 }
 
index 4b7ce640a56094d97feea9f9cc3aa8b0ee915c0e..679f20fab838d2a6a6833ad9d060c04e66739355 100644 (file)
@@ -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);
 }
index 5b65a2bbfd40940ee479c90e0b9337817e02f383..8523b7275bfcbdce984a45e1884904680630e186 100644 (file)
@@ -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);
 }
 
index c88e3b36e27e84a643ba5f1ac78e4668910f0767..4d711f8664480cac3d35f2edcec52283832e25b6 100644 (file)
@@ -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);
index 8f61f4159e64f817c6a7fd3d83f0913bd1f208b4..530ebc084beb36686597bd70b836be8da2bbd56b 100644 (file)
@@ -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);
 }
 
index 388837af67acbd36f220bf51bb84196108981eca..9bb2462a4e9551a919ae968a8f86ffb4ea9481b1 100644 (file)
@@ -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);
index f632dd9aff49a318fa2fe25fe67b739d6272a500..4515ae92f66402b5055c0bd7b79cbd3370b3897c 100644 (file)
@@ -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);
                        }
                }
        }
index 917e2bf5913c9aa9a366ed95b3d1b4b02e0dc231..a1ca89c6a8ce12e66bece1f56f2c01ed67f0f7cb 100644 (file)
@@ -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 */
index 30ad5b3777761d092646c5ceacff699c004f31bb..0ea3a3e62ebd6f30276893002da8d6b536005e96 100644 (file)
@@ -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"