Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r--source/blender/blenkernel/intern/action.c15
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c18
-rw-r--r--source/blender/blenkernel/intern/armature.c31
-rw-r--r--source/blender/blenkernel/intern/brush.c16
-rw-r--r--source/blender/blenkernel/intern/camera.c3
-rw-r--r--source/blender/blenkernel/intern/curve.c53
-rw-r--r--source/blender/blenkernel/intern/effect.c3
-rw-r--r--source/blender/blenkernel/intern/font.c3
-rw-r--r--source/blender/blenkernel/intern/gpencil.c9
-rw-r--r--source/blender/blenkernel/intern/group.c66
-rw-r--r--source/blender/blenkernel/intern/image.c13
-rw-r--r--source/blender/blenkernel/intern/key.c6
-rw-r--r--source/blender/blenkernel/intern/lamp.c2
-rw-r--r--source/blender/blenkernel/intern/lattice.c23
-rw-r--r--source/blender/blenkernel/intern/library.c270
-rw-r--r--source/blender/blenkernel/intern/library_query.c76
-rw-r--r--source/blender/blenkernel/intern/library_remap.c768
-rw-r--r--source/blender/blenkernel/intern/linestyle.c42
-rw-r--r--source/blender/blenkernel/intern/mask.c59
-rw-r--r--source/blender/blenkernel/intern/material.c42
-rw-r--r--source/blender/blenkernel/intern/mball.c23
-rw-r--r--source/blender/blenkernel/intern/mesh.c42
-rw-r--r--source/blender/blenkernel/intern/movieclip.c4
-rw-r--r--source/blender/blenkernel/intern/node.c38
-rw-r--r--source/blender/blenkernel/intern/object.c473
-rw-r--r--source/blender/blenkernel/intern/paint.c11
-rw-r--r--source/blender/blenkernel/intern/particle.c25
-rw-r--r--source/blender/blenkernel/intern/sca.c71
-rw-r--r--source/blender/blenkernel/intern/scene.c86
-rw-r--r--source/blender/blenkernel/intern/screen.c17
-rw-r--r--source/blender/blenkernel/intern/sequencer.c4
-rw-r--r--source/blender/blenkernel/intern/sound.c15
-rw-r--r--source/blender/blenkernel/intern/speaker.c5
-rw-r--r--source/blender/blenkernel/intern/text.c9
-rw-r--r--source/blender/blenkernel/intern/texture.c37
-rw-r--r--source/blender/blenkernel/intern/world.c30
36 files changed, 1084 insertions, 1324 deletions
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index df9b9683687..46ee8a4d888 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -159,22 +159,19 @@ void BKE_action_make_local(bAction *act)
/* .................................. */
+/** Free (or release) any data used by this action (does not free the action itself). */
void BKE_action_free(bAction *act)
-{
- /* sanity check */
- if (act == NULL)
- return;
-
+{
+ /* No animdata here. */
+
/* Free F-Curves */
free_fcurves(&act->curves);
/* Free groups */
- if (act->groups.first)
- BLI_freelistN(&act->groups);
+ BLI_freelistN(&act->groups);
/* Free pose-references (aka local markers) */
- if (act->markers.first)
- BLI_freelistN(&act->markers);
+ BLI_freelistN(&act->markers);
}
/* .................................. */
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 99aae6239e8..91b33f3efd3 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -216,7 +216,7 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
/* Freeing -------------------------------------------- */
/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */
-void BKE_animdata_free(ID *id)
+void BKE_animdata_free(ID *id, const bool do_id_user)
{
/* Only some ID-blocks have this info for now, so we cast the
* types that do to be of type IdAdtTemplate
@@ -227,12 +227,14 @@ void BKE_animdata_free(ID *id)
/* check if there's any AnimData to start with */
if (adt) {
- /* unlink action (don't free, as it's in its own list) */
- if (adt->action)
- id_us_min(&adt->action->id);
- /* same goes for the temporarily displaced action */
- if (adt->tmpact)
- id_us_min(&adt->tmpact->id);
+ if (do_id_user) {
+ /* unlink action (don't free, as it's in its own list) */
+ if (adt->action)
+ id_us_min(&adt->action->id);
+ /* same goes for the temporarily displaced action */
+ if (adt->tmpact)
+ id_us_min(&adt->tmpact->id);
+ }
/* free nla data */
free_nladata(&adt->nla_tracks);
@@ -292,7 +294,7 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action)
if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name)))
return false;
- BKE_animdata_free(id_to);
+ BKE_animdata_free(id_to, true);
adt = BKE_animdata_from_id(id_from);
if (adt) {
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 04b4733fd44..038993777cf 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -120,30 +120,25 @@ void BKE_armature_bonelist_free(ListBase *lb)
BLI_freelistN(lb);
}
+/** Free (or release) any data used by this armature (does not free the armature itself). */
void BKE_armature_free(bArmature *arm)
{
- if (arm) {
- BKE_armature_bonelist_free(&arm->bonebase);
+ BKE_animdata_free(&arm->id, false);
- /* free editmode data */
- if (arm->edbo) {
- BLI_freelistN(arm->edbo);
+ BKE_armature_bonelist_free(&arm->bonebase);
- MEM_freeN(arm->edbo);
- arm->edbo = NULL;
- }
+ /* free editmode data */
+ if (arm->edbo) {
+ BLI_freelistN(arm->edbo);
- /* free sketch */
- if (arm->sketch) {
- freeSketch(arm->sketch);
- arm->sketch = NULL;
- }
+ MEM_freeN(arm->edbo);
+ arm->edbo = NULL;
+ }
- /* free animation data */
- if (arm->adt) {
- BKE_animdata_free(&arm->id);
- arm->adt = NULL;
- }
+ /* free sketch */
+ if (arm->sketch) {
+ freeSketch(arm->sketch);
+ arm->sketch = NULL;
}
}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index da7863096e3..a3e006a162f 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -202,22 +202,18 @@ Brush *BKE_brush_copy(Brush *brush)
return brushn;
}
-/* not brush itself */
+/** Free (or release) any data used by this brush (does not free the brush itself). */
void BKE_brush_free(Brush *brush)
{
- id_us_min((ID *)brush->mtex.tex);
- id_us_min((ID *)brush->mask_mtex.tex);
- id_us_min((ID *)brush->paint_curve);
-
- if (brush->icon_imbuf)
+ if (brush->icon_imbuf) {
IMB_freeImBuf(brush->icon_imbuf);
-
- BKE_previewimg_free(&(brush->preview));
+ }
curvemapping_free(brush->curve);
- if (brush->gradient)
- MEM_freeN(brush->gradient);
+ MEM_SAFE_FREE(brush->gradient);
+
+ BKE_previewimg_free(&(brush->preview));
}
/**
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 96bac2c2f41..eabee742327 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -153,9 +153,10 @@ void BKE_camera_make_local(Camera *cam)
}
}
+/** Free (or release) any data used by this camera (does not free the camera itself). */
void BKE_camera_free(Camera *ca)
{
- BKE_animdata_free((ID *)ca);
+ BKE_animdata_free((ID *)ca, false);
}
/******************************** Camera Usage *******************************/
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 8afb451f768..dec6ff22360 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -69,36 +69,6 @@ static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], c
short cox, short coy,
float *lambda, float *mu, float vec[3]);
-void BKE_curve_unlink(Curve *cu)
-{
- int a;
-
- for (a = 0; a < cu->totcol; a++) {
- if (cu->mat[a])
- id_us_min(&cu->mat[a]->id);
- cu->mat[a] = NULL;
- }
- if (cu->vfont)
- id_us_min(&cu->vfont->id);
- cu->vfont = NULL;
-
- if (cu->vfontb)
- id_us_min(&cu->vfontb->id);
- cu->vfontb = NULL;
-
- if (cu->vfonti)
- id_us_min(&cu->vfonti->id);
- cu->vfonti = NULL;
-
- if (cu->vfontbi)
- id_us_min(&cu->vfontbi->id);
- cu->vfontbi = NULL;
-
- if (cu->key)
- id_us_min(&cu->key->id);
- cu->key = NULL;
-}
-
/* frees editcurve entirely */
void BKE_curve_editfont_free(Curve *cu)
{
@@ -136,26 +106,21 @@ void BKE_curve_editNurb_free(Curve *cu)
}
}
-/* don't free curve itself */
+/** Free (or release) any data used by this curve (does not free the curve itself). */
void BKE_curve_free(Curve *cu)
{
+ BKE_animdata_free((ID *)cu, false);
+
BKE_nurbList_free(&cu->nurb);
BKE_curve_editfont_free(cu);
BKE_curve_editNurb_free(cu);
- BKE_curve_unlink(cu);
- BKE_animdata_free((ID *)cu);
-
- if (cu->mat)
- MEM_freeN(cu->mat);
- if (cu->str)
- MEM_freeN(cu->str);
- if (cu->strinfo)
- MEM_freeN(cu->strinfo);
- if (cu->bb)
- MEM_freeN(cu->bb);
- if (cu->tb)
- MEM_freeN(cu->tb);
+
+ MEM_SAFE_FREE(cu->mat);
+ MEM_SAFE_FREE(cu->str);
+ MEM_SAFE_FREE(cu->strinfo);
+ MEM_SAFE_FREE(cu->bb);
+ MEM_SAFE_FREE(cu->tb);
}
void BKE_curve_init(Curve *cu)
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index f06dd6f9de4..a8268c03d95 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -139,9 +139,6 @@ void free_partdeflect(PartDeflect *pd)
if (!pd)
return;
- if (pd->tex)
- id_us_min(&pd->tex->id);
-
if (pd->rng)
BLI_rng_free(pd->rng);
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 812d1c66923..5e1f8814ed6 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -95,10 +95,9 @@ void BKE_vfont_free_data(struct VFont *vfont)
}
}
+/** Free (or release) any data used by this font (does not free the font itself). */
void BKE_vfont_free(struct VFont *vf)
{
- if (vf == NULL) return;
-
BKE_vfont_free_data(vf);
if (vf->packedfile) {
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index f3eb5430bce..af1bcd0c545 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -113,16 +113,13 @@ void free_gpencil_layers(ListBase *list)
}
/* Free all of GPencil datablock's related data, but not the block itself */
+/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
void BKE_gpencil_free(bGPdata *gpd)
{
+ BKE_animdata_free(&gpd->id, false);
+
/* free layers */
free_gpencil_layers(&gpd->layers);
-
- /* free animation data */
- if (gpd->adt) {
- BKE_animdata_free(&gpd->id);
- gpd->adt = NULL;
- }
}
/* -------- Container Creation ---------- */
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index a44eb1df9fe..4fdee7e3633 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -60,79 +60,19 @@ static void free_group_object(GroupObject *go)
MEM_freeN(go);
}
-
+/** Free (or release) any data used by this group (does not free the group itself). */
void BKE_group_free(Group *group)
{
/* don't free group itself */
GroupObject *go;
- BKE_previewimg_free(&group->preview);
+ /* No animdata here. */
while ((go = BLI_pophead(&group->gobject))) {
free_group_object(go);
}
-}
-void BKE_group_unlink(Main *bmain, Group *group)
-{
- Material *ma;
- Object *ob;
- Scene *sce;
- SceneRenderLayer *srl;
- ParticleSystem *psys;
-
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->group == group)
- ma->group = NULL;
- }
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->group == group)
- ma->group = NULL;
- }
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- Base *base = sce->base.first;
-
- /* ensure objects are not in this group */
- for (; base; base = base->next) {
- if (BKE_group_object_unlink(group, base->object, sce, base) &&
- BKE_group_object_find(NULL, base->object) == NULL)
- {
- base->object->flag &= ~OB_FROMGROUP;
- base->flag &= ~OB_FROMGROUP;
- }
- }
-
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- FreestyleLineSet *lineset;
-
- if (srl->light_override == group)
- srl->light_override = NULL;
- for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
- if (lineset->group == group)
- lineset->group = NULL;
- }
- }
- }
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
-
- if (ob->dup_group == group) {
- ob->dup_group = NULL;
- }
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- if (psys->part->dup_group == group)
- psys->part->dup_group = NULL;
-#if 0 /* not used anymore, only keps for readfile.c, no need to account for this */
- if (psys->part->eff_group == group)
- psys->part->eff_group = NULL;
-#endif
- }
- }
-
- /* group stays in library, but no members */
- BKE_group_free(group);
- group->id.us = 0;
+ BKE_previewimg_free(&group->preview);
}
Group *BKE_group_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 0b2c844cb2c..14a445649ad 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -324,20 +324,16 @@ void BKE_image_free_buffers(Image *ima)
ima->ok = IMA_OK;
}
-/* called by library too, do not free ima itself */
+/** Free (or release) any data used by this image (does not free the image itself). */
void BKE_image_free(Image *ima)
{
int a;
+ /* Also frees animdata. */
BKE_image_free_buffers(ima);
image_free_packedfiles(ima);
- BKE_icon_id_delete(&ima->id);
- ima->id.icon_id = 0;
-
- BKE_previewimg_free(&ima->preview);
-
for (a = 0; a < IMA_MAX_RENDER_SLOT; a++) {
if (ima->renders[a]) {
RE_FreeRenderResult(ima->renders[a]);
@@ -346,7 +342,10 @@ void BKE_image_free(Image *ima)
}
BKE_image_free_views(ima);
- MEM_freeN(ima->stereo3d_format);
+ MEM_SAFE_FREE(ima->stereo3d_format);
+
+ BKE_icon_id_delete(&ima->id);
+ BKE_previewimg_free(&ima->preview);
}
/* only image block itself */
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 362f41335d2..2517e2cc197 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -74,11 +74,13 @@
#define IPO_BEZTRIPLE 100
#define IPO_BPOINT 101
+
+/** Free (or release) any data used by this shapekey (does not free the key itself). */
void BKE_key_free(Key *key)
{
KeyBlock *kb;
-
- BKE_animdata_free((ID *)key);
+
+ BKE_animdata_free((ID *)key, false);
while ((kb = BLI_pophead(&key->block))) {
if (kb->data)
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 49a573489ef..692b703f721 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -234,7 +234,7 @@ void BKE_lamp_free(Lamp *la)
MEM_freeN(mtex);
}
- BKE_animdata_free((ID *)la);
+ BKE_animdata_free((ID *)la, false);
curvemapping_free(la->curfalloff);
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index b350e932281..58c0a567116 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -300,24 +300,27 @@ Lattice *BKE_lattice_copy(Lattice *lt)
return ltn;
}
+/** Free (or release) any data used by this lattice (does not free the lattice itself). */
void BKE_lattice_free(Lattice *lt)
{
- if (lt->def) MEM_freeN(lt->def);
- if (lt->dvert) BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
+ BKE_animdata_free(&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;
}
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 961b45df4e6..fe16df18813 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -84,7 +84,6 @@
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
-#include "BKE_fcurve.h"
#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_group.h"
@@ -92,7 +91,6 @@
#include "BKE_idcode.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
-#include "BKE_ipo.h"
#include "BKE_key.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
@@ -103,16 +101,12 @@
#include "BKE_material.h"
#include "BKE_main.h"
#include "BKE_mball.h"
-#include "BKE_movieclip.h"
#include "BKE_mask.h"
#include "BKE_node.h"
#include "BKE_object.h"
-#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_packedFile.h"
#include "BKE_speaker.h"
-#include "BKE_sound.h"
-#include "BKE_screen.h"
#include "BKE_scene.h"
#include "BKE_text.h"
#include "BKE_texture.h"
@@ -125,10 +119,6 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#ifdef WITH_PYTHON
-#include "BPY_extern.h"
-#endif
-
/* GS reads the memory pointed at in a specific ordering.
* only use this definition, makes little and big endian systems
* work fine, in conjunction with MAKE_ID */
@@ -182,7 +172,6 @@ void id_us_ensure_real(ID *id)
}
}
-/* Unused currently... */
void id_us_clear_real(ID *id)
{
if (id && (id->tag & LIB_TAG_EXTRAUSER)) {
@@ -232,9 +221,7 @@ void id_us_min(ID *id)
if (id->us <= limit) {
printf("ID user decrement error: %s (from '%s'): %d <= %d\n",
id->name, id->lib ? id->lib->filepath : "[Main]", id->us, limit);
- /* We cannot assert here, because of how we 'delete' datablocks currently (setting their usercount to zero),
- * this is weak but it's how it works for now. */
- /* BLI_assert(0); */
+ BLI_assert(0);
id->us = limit;
}
else {
@@ -462,37 +449,6 @@ bool id_copy(ID *id, ID **newid, bool test)
return false;
}
-bool id_unlink(ID *id, int test)
-{
- Main *mainlib = G.main;
- short type = GS(id->name);
-
- switch (type) {
- case ID_TXT:
- if (test) return true;
- BKE_text_unlink(mainlib, (Text *)id);
- break;
- case ID_GR:
- if (test) return true;
- BKE_group_unlink(mainlib, (Group *)id);
- break;
- case ID_OB:
- if (test) return true;
- BKE_object_unlink(mainlib, (Object *)id);
- break;
- }
-
- if (id->us == 0) {
- if (test) return true;
-
- BKE_libblock_free(mainlib, id);
-
- return true;
- }
-
- return false;
-}
-
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
{
ID *newid = NULL;
@@ -1111,234 +1067,12 @@ void BKE_libblock_relink(ID *id)
BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
}
-static void BKE_library_free(Library *lib)
+void BKE_library_free(Library *lib)
{
if (lib->packedfile)
freePackedFile(lib->packedfile);
}
-static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL;
-
-void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func)
-{
- free_windowmanager_cb = func;
-}
-
-static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL;
-
-void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func)
-{
- free_notifier_reference_cb = func;
-}
-
-static BKE_library_free_editor_id_reference_cb free_editor_id_reference_cb = NULL;
-
-void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func)
-{
- free_editor_id_reference_cb = func;
-}
-
-static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
-{
- ChannelDriver *driver;
- FCurve *fcu;
-
- /* find the driver this belongs to and update it */
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- driver = fcu->driver;
-
- if (driver) {
- DriverVar *dvar;
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- DRIVER_TARGETS_USED_LOOPER(dvar)
- {
- if (dtar->id == userdata)
- dtar->id = NULL;
- }
- DRIVER_TARGETS_LOOPER_END
- }
- }
- }
-}
-
-void BKE_libblock_free_data(Main *bmain, ID *id)
-{
- if (id->properties) {
- IDP_FreeProperty(id->properties);
- MEM_freeN(id->properties);
- }
-
- /* this ID may be a driver target! */
- BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
-}
-
-/* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c */
-void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user)
-{
- ID *id = idv;
- short type = GS(id->name);
- ListBase *lb = which_libbase(bmain, type);
-
- DAG_id_type_tag(bmain, type);
-
-#ifdef WITH_PYTHON
- BPY_id_release(id);
-#endif
-
- switch (type) { /* GetShort from util.h */
- case ID_SCE:
- BKE_scene_free((Scene *)id);
- break;
- case ID_LI:
- BKE_library_free((Library *)id);
- break;
- case ID_OB:
- BKE_object_free_ex((Object *)id, do_id_user);
- break;
- case ID_ME:
- BKE_mesh_free((Mesh *)id, 1);
- break;
- case ID_CU:
- BKE_curve_free((Curve *)id);
- break;
- case ID_MB:
- BKE_mball_free((MetaBall *)id);
- break;
- case ID_MA:
- BKE_material_free((Material *)id);
- break;
- case ID_TE:
- BKE_texture_free((Tex *)id);
- break;
- case ID_IM:
- BKE_image_free((Image *)id);
- break;
- case ID_LT:
- BKE_lattice_free((Lattice *)id);
- break;
- case ID_LA:
- BKE_lamp_free((Lamp *)id);
- break;
- case ID_CA:
- BKE_camera_free((Camera *) id);
- break;
- case ID_IP:
- BKE_ipo_free((Ipo *)id);
- break;
- case ID_KE:
- BKE_key_free((Key *)id);
- break;
- case ID_WO:
- BKE_world_free((World *)id);
- break;
- case ID_SCR:
- BKE_screen_free((bScreen *)id);
- break;
- case ID_VF:
- BKE_vfont_free((VFont *)id);
- break;
- case ID_TXT:
- BKE_text_free((Text *)id);
- break;
- case ID_SPK:
- BKE_speaker_free((Speaker *)id);
- break;
- case ID_SO:
- BKE_sound_free((bSound *)id);
- break;
- case ID_GR:
- BKE_group_free((Group *)id);
- break;
- case ID_AR:
- BKE_armature_free((bArmature *)id);
- break;
- case ID_AC:
- BKE_action_free((bAction *)id);
- break;
- case ID_NT:
- ntreeFreeTree_ex((bNodeTree *)id, do_id_user);
- break;
- case ID_BR:
- BKE_brush_free((Brush *)id);
- break;
- case ID_PA:
- BKE_particlesettings_free((ParticleSettings *)id);
- break;
- case ID_WM:
- if (free_windowmanager_cb)
- free_windowmanager_cb(NULL, (wmWindowManager *)id);
- break;
- case ID_GD:
- BKE_gpencil_free((bGPdata *)id);
- break;
- case ID_MC:
- BKE_movieclip_free((MovieClip *)id);
- break;
- case ID_MSK:
- BKE_mask_free(bmain, (Mask *)id);
- break;
- case ID_LS:
- BKE_linestyle_free((FreestyleLineStyle *)id);
- break;
- case ID_PAL:
- BKE_palette_free((Palette *)id);
- break;
- case ID_PC:
- BKE_paint_curve_free((PaintCurve *)id);
- break;
- }
-
- /* avoid notifying on removed data */
- BKE_main_lock(bmain);
-
- if (free_notifier_reference_cb) {
- free_notifier_reference_cb(id);
- }
-
- if (free_editor_id_reference_cb) {
- free_editor_id_reference_cb(id);
- }
-
- BLI_remlink(lb, id);
-
- BKE_libblock_free_data(bmain, id);
- BKE_main_unlock(bmain);
-
- MEM_freeN(id);
-}
-
-void BKE_libblock_free(Main *bmain, void *idv)
-{
- BKE_libblock_free_ex(bmain, idv, true);
-}
-
-void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
-{
- ID *id = idv;
-
- id_us_min(id);
-
- /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object.
- * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes,
- * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
- * fully unlinked.
- * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO.
- */
- if ((GS(id->name) == ID_OB) && (id->us == 1)) {
- id_us_clear_real(id);
- }
-
- if (id->us == 0) {
- switch (GS(id->name)) {
- case ID_OB:
- BKE_object_unlink(bmain, (Object *)id);
- break;
- }
-
- BKE_libblock_free(bmain, id);
- }
-}
-
Main *BKE_main_new(void)
{
Main *bmain = MEM_callocN(sizeof(Main), "new main");
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index 4fe408e755a..be3dde2753a 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -29,6 +29,7 @@
#include <stdlib.h>
+#include "MEM_guardedalloc.h"
#include "DNA_actuator_types.h"
#include "DNA_anim_types.h"
@@ -61,6 +62,7 @@
#include "DNA_world_types.h"
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
#include "BLI_ghash.h"
#include "BLI_linklist_stack.h"
@@ -69,6 +71,7 @@
#include "BKE_fcurve.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_rigidbody.h"
@@ -198,9 +201,24 @@ static void library_foreach_actuatorsObjectLooper(
FOREACH_FINALIZE_VOID;
}
+static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip)
+{
+ NlaStrip *substrip;
+
+ FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_USER);
+
+ for (substrip = strip->strips.first; substrip; substrip = substrip->next) {
+ library_foreach_nla_strip(data, substrip);
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
+
static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt)
{
FCurve *fcu;
+ NlaTrack *nla_track;
+ NlaStrip *nla_strip;
for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
ChannelDriver *driver = fcu->driver;
@@ -216,6 +234,15 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *
}
}
+ FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_USER);
+ FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_USER);
+
+ for (nla_track = adt->nla_tracks.first; nla_track; nla_track = nla_track->next) {
+ for (nla_strip = nla_track->strips.first; nla_strip; nla_strip = nla_strip->next) {
+ library_foreach_nla_strip(data, nla_strip);
+ }
+ }
+
FOREACH_FINALIZE_VOID;
}
@@ -276,6 +303,12 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
switch (GS(id->name)) {
+ case ID_LI:
+ {
+ Library *lib = (Library *) id;
+ CALLBACK_INVOKE(lib->parent, IDWALK_NOP);
+ break;
+ }
case ID_SCE:
{
Scene *scene = (Scene *) id;
@@ -287,7 +320,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
CALLBACK_INVOKE(scene->world, IDWALK_USER);
CALLBACK_INVOKE(scene->set, IDWALK_NOP);
CALLBACK_INVOKE(scene->clip, IDWALK_USER);
- CALLBACK_INVOKE(scene->nodetree, IDWALK_NOP);
+ if (scene->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_link((ID *)scene->nodetree, callback, user_data, flag);
+ }
/* DO NOT handle scene->basact here, it's doubling with the loop over whole scene->base later,
* since basact is just a pointer to one of those items. */
CALLBACK_INVOKE(scene->obedit, IDWALK_NOP);
@@ -438,6 +474,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data);
}
+ if (object->soft && object->soft->effector_weights) {
+ CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP);
+ }
+
BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data);
BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data);
BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data);
@@ -489,7 +529,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
library_foreach_mtex(&data, material->mtex[i]);
}
}
- CALLBACK_INVOKE(material->nodetree, IDWALK_NOP);
+ if (material->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_link((ID *)material->nodetree, callback, user_data, flag);
+ }
CALLBACK_INVOKE(material->group, IDWALK_USER);
break;
}
@@ -497,7 +540,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_TE:
{
Tex *texture = (Tex *) id;
- CALLBACK_INVOKE(texture->nodetree, IDWALK_NOP);
+ if (texture->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_link((ID *)texture->nodetree, callback, user_data, flag);
+ }
CALLBACK_INVOKE(texture->ima, IDWALK_USER);
if (texture->env) {
CALLBACK_INVOKE(texture->env->object, IDWALK_NOP);
@@ -527,7 +573,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
library_foreach_mtex(&data, lamp->mtex[i]);
}
}
- CALLBACK_INVOKE(lamp->nodetree, IDWALK_NOP);
+ if (lamp->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_link((ID *)lamp->nodetree, callback, user_data, flag);
+ }
break;
}
@@ -560,7 +609,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
library_foreach_mtex(&data, world->mtex[i]);
}
}
- CALLBACK_INVOKE(world->nodetree, IDWALK_NOP);
+ if (world->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_link((ID *)world->nodetree, callback, user_data, flag);
+ }
break;
}
@@ -700,7 +752,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
library_foreach_mtex(&data, linestyle->mtex[i]);
}
}
- CALLBACK_INVOKE(linestyle->nodetree, IDWALK_NOP);
+ if (linestyle->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_link((ID *)linestyle->nodetree, callback, user_data, flag);
+ }
for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) {
if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
@@ -769,11 +824,18 @@ typedef struct IDUsersIter {
int count; /* Set by callback. */
} IDUsersIter;
-static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int UNUSED(cb_flag))
+static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int cb_flag)
{
IDUsersIter *iter = user_data;
if (*id_p && (*id_p == iter->id)) {
+#if 0
+ printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d)\n",
+ iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0,
+ (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0);
+#else
+ UNUSED_VARS(cb_flag);
+#endif
iter->count++;
}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
new file mode 100644
index 00000000000..4bde0752ef3
--- /dev/null
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -0,0 +1,768 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/library_remap.c
+ * \ingroup bke
+ *
+ * Contains management of ID's and libraries remap, unlink and free logic.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <assert.h>
+
+#include "MEM_guardedalloc.h"
+
+/* all types are needed here, in order to do memory operations */
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_group_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_linestyle_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_movieclip_types.h"
+#include "DNA_mask_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_speaker_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_text_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_world_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_action.h"
+#include "BKE_animsys.h"
+#include "BKE_armature.h"
+#include "BKE_brush.h"
+#include "BKE_camera.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
+#include "BKE_font.h"
+#include "BKE_group.h"
+#include "BKE_gpencil.h"
+#include "BKE_idprop.h"
+#include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_lamp.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
+#include "BKE_linestyle.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_main.h"
+#include "BKE_mball.h"
+#include "BKE_movieclip.h"
+#include "BKE_mask.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_speaker.h"
+#include "BKE_sound.h"
+#include "BKE_screen.h"
+#include "BKE_scene.h"
+#include "BKE_text.h"
+#include "BKE_texture.h"
+#include "BKE_world.h"
+
+#ifdef WITH_PYTHON
+#include "BPY_extern.h"
+#endif
+
+static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL;
+
+void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func)
+{
+ free_windowmanager_cb = func;
+}
+
+static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL;
+
+void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func)
+{
+ free_notifier_reference_cb = func;
+}
+
+static BKE_library_remap_editor_id_reference_cb remap_editor_id_reference_cb = NULL;
+
+void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func)
+{
+ remap_editor_id_reference_cb = func;
+}
+
+typedef struct IDRemap {
+ ID *old_id;
+ ID *new_id;
+ ID *id; /* The ID in which we are replacing old_id by new_id usages. */
+ short flag;
+
+ /* 'Output' data. */
+ short status;
+ int skipped_direct; /* Number of direct usecases that could not be remapped (e.g.: obdata when in edit mode). */
+ int skipped_indirect; /* Number of indirect usecases that could not be remapped. */
+ int skipped_refcounted; /* Number of skipped usecases that refcount the datablock. */
+} IDRemap;
+
+/* IDRemap->flag enums defined in BKE_library.h */
+
+/* IDRemap->status */
+enum {
+ /* *** Set by callback. *** */
+ ID_REMAP_IS_LINKED_DIRECT = 1 << 0, /* new_id is directly linked in current .blend. */
+ ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* There was some skipped 'user_one' usages of old_id. */
+};
+
+static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), ID **id_p, int cb_flag)
+{
+ IDRemap *id_remap_data = user_data;
+ ID *old_id = id_remap_data->old_id;
+ ID *new_id = id_remap_data->new_id;
+ ID *id = id_remap_data->id;
+
+ if (!old_id) { /* Used to cleanup all IDs used by a specific one. */
+ BLI_assert(!new_id);
+ old_id = *id_p;
+ }
+
+ if (*id_p && (*id_p == old_id)) {
+ /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
+ * on the other hand since they get reset to lib data on file open/reload it is indirect too...
+ * Edit Mode is also a 'skip direct' case. */
+ const bool is_obj = (GS(id->name) == ID_OB);
+ const bool is_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group));
+ const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
+ /* Note that indirect data from same file as processed ID is **not** considered indirect! */
+ const bool is_indirect = ((id->lib != NULL) && (id->lib != old_id->lib));
+ const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
+ const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) &&
+ (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
+ const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
+
+ if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_NEVER_NULL)) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+
+ /* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */
+ if ((is_never_null && skip_never_null) ||
+ (is_obj_editmode && (((Object *)id)->data == *id_p)) ||
+ (skip_indirect && (is_proxy || is_indirect)))
+ {
+ if (is_never_null || is_proxy || is_obj_editmode) {
+ id_remap_data->skipped_direct++;
+ }
+ else {
+ id_remap_data->skipped_indirect++;
+ }
+ if (cb_flag & IDWALK_USER) {
+ id_remap_data->skipped_refcounted++;
+ }
+ else if (cb_flag & IDWALK_USER_ONE) {
+ /* No need to count number of times this happens, just a flag is enough. */
+ id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED;
+ }
+ }
+ else {
+ if (!is_never_null) {
+ *id_p = new_id;
+ }
+ if (cb_flag & IDWALK_USER) {
+ id_us_min(old_id);
+ /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
+ if (new_id)
+ new_id->us++;
+ }
+ else if (cb_flag & IDWALK_USER_ONE) {
+ id_us_ensure_real(new_id);
+ /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed,
+ * that extra user is processed in final handling... */
+ }
+ if (!is_indirect) {
+ id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
+ }
+ }
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/**
+ * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
+ *
+ * Behavior differs depending on whether given \a id is NULL or not:
+ * - \a id NULL: \a old_id must be non-NULL, \a new_id may be NULL (unlinking \a old_id) or not
+ * (remapping \a old_id to \a new_id). The whole \a bmain database is checked, and all pointers to \a old_id
+ * are remapped to \a new_id.
+ * - \a id is non-NULL:
+ * + If \a old_id is NULL, \a new_id must also be NULL, and all ID pointers from \a id are cleared (i.e. \a id
+ * does not references any other datablock anymore).
+ * + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only for given \a id.
+ *
+ * \param bmain: the Main data storage to operate on (can be NULL if \a id is non-NULL).
+ * \param id: the datablock to operate on (can be NULL if \a bmain is non-NULL).
+ * \param old_id: the datablock to dereference (may be NULL if \a id is non-NULL).
+ * \param new_id: the new datablock to replace \a old_id references with (may be NULL).
+ * \param r_id_remap_data: if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process).
+ */
+static void libblock_remap_data(
+ Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data)
+{
+ IDRemap id_remap_data;
+ ListBase *lb_array[MAX_LIBARRAY];
+ int i;
+
+ if (r_id_remap_data == NULL) {
+ r_id_remap_data = &id_remap_data;
+ }
+ r_id_remap_data->old_id = old_id;
+ r_id_remap_data->new_id = new_id;
+ r_id_remap_data->id = NULL;
+ r_id_remap_data->flag = remap_flags;
+ r_id_remap_data->status = 0;
+ r_id_remap_data->skipped_direct = 0;
+ r_id_remap_data->skipped_indirect = 0;
+ r_id_remap_data->skipped_refcounted = 0;
+
+ if (id) {
+#ifdef DEBUG_PRINT
+ printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
+#endif
+ r_id_remap_data->id = id;
+ BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+ }
+ else {
+ i = set_listbasepointers(bmain, lb_array);
+
+ /* Note that this is a very 'bruteforce' approach, maybe we could use some depsgraph to only process
+ * objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */
+
+ while (i--) {
+ ID *id_curr = lb_array[i]->first;
+
+ for (; id_curr; id_curr = id_curr->next) {
+ /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
+ * the user count handling...
+ * XXX No more true (except for debug usage of those skipping counters). */
+ r_id_remap_data->id = id_curr;
+ BKE_library_foreach_ID_link(
+ id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP);
+ }
+ }
+ }
+
+ /* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior
+ * though, we can always add an option (flag) to control this later if needed. */
+ if (old_id && (old_id->flag & LIB_FAKEUSER)) {
+ id_fake_user_clear(old_id);
+ id_fake_user_set(new_id);
+ }
+
+ id_us_clear_real(old_id);
+
+ if (new_id && (new_id->tag & LIB_TAG_INDIRECT) && (r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) {
+ new_id->tag &= ~LIB_TAG_INDIRECT;
+ new_id->tag |= LIB_TAG_EXTERN;
+ }
+
+#ifdef DEBUG_PRINT
+ printf("%s: %d occurences skipped (%d direct and %d indirect ones)\n", __func__,
+ r_id_remap_data->skipped_direct + r_id_remap_data->skipped_indirect,
+ r_id_remap_data->skipped_direct, r_id_remap_data->skipped_indirect);
+#endif
+}
+
+/**
+ * Replace all references in given Main to \a old_id by \a new_id
+ * (if \a new_id is NULL, it unlinks \a old_id).
+ */
+void BKE_libblock_remap_locked(
+ Main *bmain, void *old_idv, void *new_idv,
+ const short remap_flags)
+{
+ IDRemap id_remap_data;
+ ID *old_id = old_idv;
+ ID *new_id = new_idv;
+ int skipped_direct, skipped_refcounted;
+
+ BLI_assert(old_id != NULL);
+ BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
+ BLI_assert(old_id != new_id);
+
+ /* Some pre-process updates.
+ * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
+ */
+ if (GS(old_id->name) == ID_OB) {
+ Object *old_ob = (Object *)old_id;
+ Object *new_ob = (Object *)new_id;
+
+ if (new_ob == NULL) {
+ Scene *sce;
+ Base *base;
+
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
+ base = BKE_scene_base_find(sce, old_ob);
+
+ if (base) {
+ id_us_min((ID *)base->object);
+ BKE_scene_base_unlink(sce, base);
+ MEM_freeN(base);
+ }
+ }
+ }
+ }
+
+ libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data);
+
+ if (free_notifier_reference_cb) {
+ free_notifier_reference_cb(old_id);
+ }
+
+ /* We assume editors do not hold references to their IDs... This is false in some cases
+ * (Image is especially tricky here), editors' code is to handle refcount (id->us) itself then. */
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(old_id, new_id);
+ }
+
+ skipped_direct = id_remap_data.skipped_direct;
+ skipped_refcounted = id_remap_data.skipped_refcounted;
+
+ /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user count has actually
+ * been incremented for that, we have to decrease once more its user count... unless we had to skip
+ * some 'user_one' cases. */
+ if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) {
+ id_us_min(old_id);
+ old_id->tag &= ~LIB_TAG_EXTRAUSER_SET;
+ }
+
+ BLI_assert(old_id->us - skipped_refcounted >= 0);
+ UNUSED_VARS_NDEBUG(skipped_refcounted);
+
+ if (skipped_direct == 0) {
+ /* old_id is assumed to not be used directly anymore... */
+ if (old_id->lib && (old_id->tag & LIB_TAG_EXTERN)) {
+ old_id->tag &= ~LIB_TAG_EXTERN;
+ old_id->tag |= LIB_TAG_INDIRECT;
+ }
+ }
+
+ /* Some after-process updates.
+ * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
+ */
+ switch (GS(old_id->name)) {
+ case ID_OB:
+ {
+ Object *old_ob = (Object *)old_id;
+ Object *new_ob = (Object *)new_id;
+
+ if (old_ob->flag & OB_FROMGROUP) {
+ /* Note that for Scene's BaseObject->flag, either we:
+ * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already.
+ * - remaped old_ob by new_ob, in which case scenes' bases are still valid as is.
+ * So in any case, no need to update them here. */
+ if (BKE_group_object_find(NULL, old_ob) == NULL) {
+ old_ob->flag &= ~OB_FROMGROUP;
+ }
+ if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */
+ Group *group;
+ for (group = bmain->group.first; group; group = group->id.next) {
+ BKE_group_object_unlink(group, NULL, NULL, NULL);
+ }
+ }
+ else {
+ new_ob->flag |= OB_FROMGROUP;
+ }
+ }
+ break;
+ }
+ case ID_GR:
+ if (new_id == NULL) { /* Only affects us in case group was unlinked. */
+ for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
+ /* Note that here we assume no object has no base (i.e. all objects are assumed instanced
+ * in one scene...). */
+ for (Base *base = sce->base.first; base; base = base->next) {
+ if (base->flag & OB_FROMGROUP) {
+ Object *ob = base->object;
+
+ if (ob->flag & OB_FROMGROUP) {
+ Group *grp = BKE_group_object_find(NULL, ob);
+
+ /* Unlinked group (old_id) is still in bmain... */
+ if (grp && (&grp->id == old_id)) {
+ grp = BKE_group_object_find(grp, ob);
+ }
+ if (!grp) {
+ ob->flag &= ~OB_FROMGROUP;
+ }
+ }
+ if (!(ob->flag & OB_FROMGROUP)) {
+ base->flag &= ~OB_FROMGROUP;
+ }
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Full rebuild of DAG! */
+ DAG_relations_tag_update(bmain);
+}
+
+void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
+{
+ BKE_main_lock(bmain);
+
+ BKE_libblock_remap_locked(bmain, old_idv, new_idv, remap_flags);
+
+ BKE_main_unlock(bmain);
+}
+
+/**
+ * Unlink given \a id from given \a bmain (does not touch to indirect, i.e. library, usages of the ID).
+ *
+ * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by \a LIB_TAG_DOIT flag
+ * (quite obviously, 'non-NULL' usages can never be unlinked by this function...).
+ */
+void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null)
+{
+ const short remap_flags = ID_REMAP_SKIP_INDIRECT_USAGE | (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0);
+
+ BKE_main_lock(bmain);
+
+ BKE_libblock_remap_locked(bmain, idv, NULL, remap_flags);
+
+ BKE_main_unlock(bmain);
+}
+
+/** Similar to libblock_remap, but only affects IDs used by given \a idv ID.
+ *
+ * \param old_idv: Unlike BKE_libblock_remap, can be NULL,
+ * in which case all ID usages by given \a idv will be cleared.
+ * \param us_min_never_null: If \a true and new_id is NULL,
+ * 'NEVER_NULL' ID usages keep their old id, but this one still gets its user count decremented
+ * (needed when given \a idv is going to be deleted right after being unlinked).
+ */
+/* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */
+/* XXX Arg! Naming... :(
+ * _relink? avoids confusion with _remap, but is confusing with _unlink
+ * _remap_used_ids?
+ * _remap_datablocks?
+ * BKE_id_remap maybe?
+ * ... sigh
+ */
+void BKE_libblock_relink_ex(
+ void *idv, void *old_idv, void *new_idv, const bool us_min_never_null)
+{
+ ID *id = idv;
+ ID *old_id = old_idv;
+ ID *new_id = new_idv;
+ int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE;
+
+ /* No need to lock here, we are only affecting given ID. */
+
+ BLI_assert(id);
+ if (old_id) {
+ BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
+ BLI_assert(old_id != new_id);
+ }
+ else {
+ BLI_assert(new_id == NULL);
+ }
+
+ libblock_remap_data(NULL, id, old_id, new_id, remap_flags, NULL);
+}
+
+static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata)
+{
+ ChannelDriver *driver;
+ FCurve *fcu;
+
+ /* find the driver this belongs to and update it */
+ for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ driver = fcu->driver;
+
+ if (driver) {
+ DriverVar *dvar;
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ if (dtar->id == userdata)
+ dtar->id = NULL;
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
+ }
+ }
+}
+
+void BKE_libblock_free_data(Main *bmain, ID *id)
+{
+ if (id->properties) {
+ IDP_FreeProperty(id->properties);
+ MEM_freeN(id->properties);
+ }
+
+ /* this ID may be a driver target! */
+ BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
+}
+
+/**
+ * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c
+ *
+ * \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv.
+ */
+void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
+{
+ ID *id = idv;
+ short type = GS(id->name);
+ ListBase *lb = which_libbase(bmain, type);
+
+ DAG_id_type_tag(bmain, type);
+
+#ifdef WITH_PYTHON
+ BPY_id_release(id);
+#endif
+
+ if (do_id_user) {
+ BKE_libblock_relink_ex(id, NULL, NULL, true);
+ }
+
+ switch (type) {
+ case ID_SCE:
+ BKE_scene_free((Scene *)id);
+ break;
+ case ID_LI:
+ BKE_library_free((Library *)id);
+ break;
+ case ID_OB:
+ BKE_object_free((Object *)id);
+ break;
+ case ID_ME:
+ BKE_mesh_free((Mesh *)id);
+ break;
+ case ID_CU:
+ BKE_curve_free((Curve *)id);
+ break;
+ case ID_MB:
+ BKE_mball_free((MetaBall *)id);
+ break;
+ case ID_MA:
+ BKE_material_free((Material *)id);
+ break;
+ case ID_TE:
+ BKE_texture_free((Tex *)id);
+ break;
+ case ID_IM:
+ BKE_image_free((Image *)id);
+ break;
+ case ID_LT:
+ BKE_lattice_free((Lattice *)id);
+ break;
+ case ID_LA:
+ BKE_lamp_free((Lamp *)id);
+ break;
+ case ID_CA:
+ BKE_camera_free((Camera *) id);
+ break;
+ case ID_IP: /* Deprecated. */
+ BKE_ipo_free((Ipo *)id);
+ break;
+ case ID_KE:
+ BKE_key_free((Key *)id);
+ break;
+ case ID_WO:
+ BKE_world_free((World *)id);
+ break;
+ case ID_SCR:
+ BKE_screen_free((bScreen *)id);
+ break;
+ case ID_VF:
+ BKE_vfont_free((VFont *)id);
+ break;
+ case ID_TXT:
+ BKE_text_free((Text *)id);
+ break;
+ case ID_SPK:
+ BKE_speaker_free((Speaker *)id);
+ break;
+ case ID_SO:
+ BKE_sound_free((bSound *)id);
+ break;
+ case ID_GR:
+ BKE_group_free((Group *)id);
+ break;
+ case ID_AR:
+ BKE_armature_free((bArmature *)id);
+ break;
+ case ID_AC:
+ BKE_action_free((bAction *)id);
+ break;
+ case ID_NT:
+ ntreeFreeTree((bNodeTree *)id);
+ break;
+ case ID_BR:
+ BKE_brush_free((Brush *)id);
+ break;
+ case ID_PA:
+ BKE_particlesettings_free((ParticleSettings *)id);
+ break;
+ case ID_WM:
+ if (free_windowmanager_cb)
+ free_windowmanager_cb(NULL, (wmWindowManager *)id);
+ break;
+ case ID_GD:
+ BKE_gpencil_free((bGPdata *)id);
+ break;
+ case ID_MC:
+ BKE_movieclip_free((MovieClip *)id);
+ break;
+ case ID_MSK:
+ BKE_mask_free((Mask *)id);
+ break;
+ case ID_LS:
+ BKE_linestyle_free((FreestyleLineStyle *)id);
+ break;
+ case ID_PAL:
+ BKE_palette_free((Palette *)id);
+ break;
+ case ID_PC:
+ BKE_paint_curve_free((PaintCurve *)id);
+ break;
+ }
+
+ /* avoid notifying on removed data */
+ BKE_main_lock(bmain);
+
+ if (free_notifier_reference_cb) {
+ free_notifier_reference_cb(id);
+ }
+
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(id, NULL);
+ }
+
+ BLI_remlink(lb, id);
+
+ BKE_libblock_free_data(bmain, id);
+ BKE_main_unlock(bmain);
+
+ MEM_freeN(id);
+}
+
+void BKE_libblock_free(Main *bmain, void *idv)
+{
+ BKE_libblock_free_ex(bmain, idv, true);
+}
+
+void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
+{
+ ID *id = idv;
+
+ id_us_min(id);
+
+ /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object.
+ * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes,
+ * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
+ * fully unlinked.
+ * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO.
+ */
+ if ((GS(id->name) == ID_OB) && (id->us == 1)) {
+ id_us_clear_real(id);
+ }
+
+ if (id->us == 0) {
+ BKE_libblock_unlink(bmain, id, false);
+
+ BKE_libblock_free(bmain, id);
+ }
+}
+
+void BKE_libblock_delete(Main *bmain, void *idv)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(bmain, lbarray);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+
+ /* First tag all datablocks directly from target lib.
+ * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects).
+ * Avoids to have to loop twice. */
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ /* Note: in case we delete a library, we also delete all its datablocks! */
+ if ((id == (ID *)idv) || (id->lib == (Library *)idv) || (id->tag & LIB_TAG_DOIT)) {
+ id->tag |= LIB_TAG_DOIT;
+ /* Will tag 'never NULL' users of this ID too.
+ * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect (and proxy!)
+ * links, this can lead to nasty crashing here in second, actual deleting loop.
+ * Also, this will also flag users of deleted data that cannot be unlinked
+ * (object using deleted obdata, etc.), so that they also get deleted. */
+ BKE_libblock_remap(bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE);
+ }
+ }
+ }
+
+ /* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones, have been already cleared
+ * when we reach it (e.g. Objects being processed before meshes, they'll have already released their 'reference'
+ * over meshes when we come to freeing obdata). */
+ for (i = base_count; i--; ) {
+ ListBase *lb = lbarray[i];
+ ID *id, *id_next;
+
+ for (id = lb->first; id; id = id_next) {
+ id_next = id->next;
+ if (id->tag & LIB_TAG_DOIT) {
+ if (id->us != 0) {
+#ifdef DEBUG_PRINT
+ printf("%s: deleting %s (%d)\n", __func__, id->name, id->us);
+#endif
+ BLI_assert(id->us == 0);
+ }
+ BKE_libblock_free(bmain, id);
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 5a1dfc04045..30dc48819e9 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -125,26 +125,25 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name)
return linestyle;
}
+/** Free (or release) any data used by this linestyle (does not free the linestyle itself). */
void BKE_linestyle_free(FreestyleLineStyle *linestyle)
{
LineStyleModifier *m;
-
- MTex *mtex;
int a;
+ BKE_animdata_free(&linestyle->id, false);
+
for (a = 0; a < MAX_MTEX; a++) {
- mtex = linestyle->mtex[a];
- if (mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
+ MEM_SAFE_FREE(linestyle->mtex[a]);
}
+
+ /* is no lib link block, but linestyle extension */
if (linestyle->nodetree) {
ntreeFreeTree(linestyle->nodetree);
MEM_freeN(linestyle->nodetree);
+ linestyle->nodetree = NULL;
}
- BKE_animdata_free(&linestyle->id);
while ((m = (LineStyleModifier *)linestyle->color_modifiers.first))
BKE_linestyle_color_modifier_remove(linestyle, m);
while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first))
@@ -1452,33 +1451,6 @@ char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand
return NULL;
}
-void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob)
-{
- LineStyleModifier *m;
-
- for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) {
- if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- if (((LineStyleColorModifier_DistanceFromObject *)m)->target == ob) {
- ((LineStyleColorModifier_DistanceFromObject *)m)->target = NULL;
- }
- }
- }
- for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next) {
- if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- if (((LineStyleAlphaModifier_DistanceFromObject *)m)->target == ob) {
- ((LineStyleAlphaModifier_DistanceFromObject *)m)->target = NULL;
- }
- }
- }
- for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next) {
- if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- if (((LineStyleThicknessModifier_DistanceFromObject *)m)->target == ob) {
- ((LineStyleThicknessModifier_DistanceFromObject *)m)->target = NULL;
- }
- }
- }
-}
-
bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes)
{
if (use_shading_nodes) {
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 930a3c487ec..94e53755ac4 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -1010,63 +1010,10 @@ void BKE_mask_layer_free_list(ListBase *masklayers)
}
}
-/** free for temp copy, but don't manage unlinking from other pointers */
-void BKE_mask_free_nolib(Mask *mask)
+/** Free (or release) any data used by this mask (does not free the mask itself). */
+void BKE_mask_free(Mask *mask)
{
- BKE_mask_layer_free_list(&mask->masklayers);
-}
-
-void BKE_mask_free(Main *bmain, Mask *mask)
-{
- bScreen *scr;
- ScrArea *area;
- SpaceLink *sl;
- Scene *scene;
-
- for (scr = bmain->screen.first; scr; scr = scr->id.next) {
- for (area = scr->areabase.first; area; area = area->next) {
- for (sl = area->spacedata.first; sl; sl = sl->next) {
- switch (sl->spacetype) {
- case SPACE_CLIP:
- {
- SpaceClip *sc = (SpaceClip *)sl;
-
- if (sc->mask_info.mask == mask) {
- sc->mask_info.mask = NULL;
- }
- break;
- }
- case SPACE_IMAGE:
- {
- SpaceImage *sima = (SpaceImage *)sl;
-
- if (sima->mask_info.mask == mask) {
- sima->mask_info.mask = NULL;
- }
- break;
- }
- }
- }
- }
- }
-
- for (scene = bmain->scene.first; scene; scene = scene->id.next) {
- if (scene->ed) {
- Sequence *seq;
-
- SEQ_BEGIN (scene->ed, seq)
- {
- if (seq->mask == mask) {
- seq->mask = NULL;
- }
- }
- SEQ_END
- }
- }
-
- FOREACH_NODETREE(bmain, ntree, id) {
- BKE_node_tree_unlink_id((ID *)mask, ntree);
- } FOREACH_NODETREE_END
+ BKE_animdata_free((ID *)mask, false);
/* free mask data */
BKE_mask_layer_free_list(&mask->masklayers);
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 30f82a50ed9..db5ac54ada9 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -81,47 +81,33 @@ void init_def_material(void)
BKE_material_init(&defmaterial);
}
-/* not material itself */
+/** Free (or release) any data used by this material (does not free the material itself). */
void BKE_material_free(Material *ma)
{
- BKE_material_free_ex(ma, true);
-}
-
-/* not material itself */
-void BKE_material_free_ex(Material *ma, bool do_id_user)
-{
- MTex *mtex;
int a;
+
+ BKE_animdata_free((ID *)ma, false);
for (a = 0; a < MAX_MTEX; a++) {
- mtex = ma->mtex[a];
- if (do_id_user && mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
+ MEM_SAFE_FREE(ma->mtex[a]);
}
- if (ma->ramp_col) MEM_freeN(ma->ramp_col);
- if (ma->ramp_spec) MEM_freeN(ma->ramp_spec);
-
- BKE_animdata_free((ID *)ma);
-
- if (ma->preview)
- BKE_previewimg_free(&ma->preview);
- BKE_icon_id_delete((struct ID *)ma);
- ma->id.icon_id = 0;
+ MEM_SAFE_FREE(ma->ramp_col);
+ MEM_SAFE_FREE(ma->ramp_spec);
/* is no lib link block, but material extension */
if (ma->nodetree) {
- ntreeFreeTree_ex(ma->nodetree, do_id_user);
+ ntreeFreeTree(ma->nodetree);
MEM_freeN(ma->nodetree);
+ ma->nodetree = NULL;
}
- if (ma->texpaintslot)
- MEM_freeN(ma->texpaintslot);
+ MEM_SAFE_FREE(ma->texpaintslot);
+
+ GPU_material_free(&ma->gpumaterial);
- if (ma->gpumaterial.first)
- GPU_material_free(&ma->gpumaterial);
+ BKE_icon_id_delete((ID *)ma);
+ BKE_previewimg_free(&ma->preview);
}
void BKE_material_init(Material *ma)
@@ -1840,7 +1826,7 @@ void free_matcopybuf(void)
matcopybuf.ramp_spec = NULL;
if (matcopybuf.nodetree) {
- ntreeFreeTree_ex(matcopybuf.nodetree, false);
+ ntreeFreeTree(matcopybuf.nodetree);
MEM_freeN(matcopybuf.nodetree);
matcopybuf.nodetree = NULL;
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index d7019aa8458..685cd35fc20 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -66,28 +66,13 @@
/* Functions */
-void BKE_mball_unlink(MetaBall *mb)
+/** Free (or release) any data used by this mball (does not free the mball itself). */
+void BKE_mball_free(MetaBall *mb)
{
- int a;
-
- for (a = 0; a < mb->totcol; a++) {
- if (mb->mat[a])
- id_us_min(&mb->mat[a]->id);
- mb->mat[a] = NULL;
- }
-}
+ BKE_animdata_free((ID *)mb, false);
+ MEM_SAFE_FREE(mb->mat);
-/* do not free mball itself */
-void BKE_mball_free(MetaBall *mb)
-{
- BKE_mball_unlink(mb);
-
- if (mb->adt) {
- BKE_animdata_free((ID *)mb);
- mb->adt = NULL;
- }
- if (mb->mat) MEM_freeN(mb->mat);
BLI_freelistN(&mb->elems);
if (mb->disp.first) BKE_displist_free(&mb->disp);
}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 2af78cca79f..4e47dfcce74 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -432,33 +432,11 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me)
* we need a more generic method, like the expand() functions in
* readfile.c */
-void BKE_mesh_unlink(Mesh *me)
-{
- int a;
-
- if (me == NULL) return;
-
- if (me->mat) {
- for (a = 0; a < me->totcol; a++) {
- if (me->mat[a])
- id_us_min(&me->mat[a]->id);
- me->mat[a] = NULL;
- }
- }
- if (me->key) {
- id_us_min(&me->key->id);
- }
- me->key = NULL;
-
- if (me->texcomesh) me->texcomesh = NULL;
-}
-
-/* do not free mesh itself */
-void BKE_mesh_free(Mesh *me, int unlink)
+/** Free (or release) any data used by this mesh (does not free the mesh itself). */
+void BKE_mesh_free(Mesh *me)
{
- if (unlink)
- BKE_mesh_unlink(me);
+ BKE_animdata_free(&me->id, false);
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
@@ -466,16 +444,10 @@ void BKE_mesh_free(Mesh *me, int unlink)
CustomData_free(&me->ldata, me->totloop);
CustomData_free(&me->pdata, me->totpoly);
- if (me->adt) {
- BKE_animdata_free(&me->id);
- me->adt = NULL;
- }
-
- if (me->mat) MEM_freeN(me->mat);
-
- if (me->bb) MEM_freeN(me->bb);
- if (me->mselect) MEM_freeN(me->mselect);
- if (me->edit_btmesh) MEM_freeN(me->edit_btmesh);
+ MEM_SAFE_FREE(me->mat);
+ MEM_SAFE_FREE(me->bb);
+ MEM_SAFE_FREE(me->mselect);
+ MEM_SAFE_FREE(me->edit_btmesh);
}
static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata)
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index d2bfcfb0887..5f667732b04 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -1248,7 +1248,7 @@ static void free_buffers(MovieClip *clip)
clip->anim = NULL;
}
- BKE_animdata_free((ID *) clip);
+ BKE_animdata_free((ID *) clip, false);
}
void BKE_movieclip_clear_cache(MovieClip *clip)
@@ -1482,8 +1482,10 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip, ImBuf *ibuf, stru
}
}
+/** Free (or release) any data used by this movie clip (does not free the clip itself). */
void BKE_movieclip_free(MovieClip *clip)
{
+ /* Also frees animdata. */
free_buffers(clip);
BKE_tracking_free(&clip->tracking);
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 2b381f6ff0b..d78ddc41e97 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -1782,21 +1782,21 @@ static void free_localized_node_groups(bNodeTree *ntree)
for (node = ntree->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP && node->id) {
bNodeTree *ngroup = (bNodeTree *)node->id;
- ntreeFreeTree_ex(ngroup, false);
+ ntreeFreeTree(ngroup);
MEM_freeN(ngroup);
}
}
}
-/* do not free ntree itself here, BKE_libblock_free calls this function too */
-void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
+/** Free (or release) any data used by this nodetree (does not free the nodetree itself). */
+void ntreeFreeTree(bNodeTree *ntree)
{
bNodeTree *tntree;
bNode *node, *next;
bNodeSocket *sock, *nextsock;
-
- if (ntree == NULL) return;
-
+
+ BKE_animdata_free((ID *)ntree, false);
+
/* XXX hack! node trees should not store execution graphs at all.
* This should be removed when old tree types no longer require it.
* Currently the execution data for texture nodes remains in the tree
@@ -1820,29 +1820,10 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
/* unregister associated RNA types */
ntreeInterfaceTypeFree(ntree);
- BKE_animdata_free((ID *)ntree);
-
- id_us_min((ID *)ntree->gpd);
-
BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */
for (node = ntree->nodes.first; node; node = next) {
next = node->next;
-
- /* ntreeUserIncrefID inline */
-
- /* XXX, this is correct, however when freeing the entire database
- * this ends up accessing freed data which isn't properly unlinking
- * its self from scene nodes, SO - for now prefer invalid usercounts
- * on free rather then bad memory access - Campbell */
-#if 0
- if (do_id_user) {
- id_us_min(node->id);
- }
-#else
- (void)do_id_user;
-#endif
-
node_free_node_ex(ntree, node, false, false);
}
@@ -1874,11 +1855,6 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
BKE_libblock_free_data(G.main, &ntree->id);
}
}
-/* same as ntreeFreeTree_ex but always manage users */
-void ntreeFreeTree(bNodeTree *ntree)
-{
- ntreeFreeTree_ex(ntree, true);
-}
void ntreeFreeCache(bNodeTree *ntree)
{
@@ -2165,7 +2141,7 @@ void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree)
if (ntree->typeinfo->local_merge)
ntree->typeinfo->local_merge(localtree, ntree);
- ntreeFreeTree_ex(localtree, false);
+ ntreeFreeTree(localtree);
MEM_freeN(localtree);
}
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 65ee153e00b..d4ba70ee0a6 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -317,14 +317,14 @@ void BKE_object_free_derived_caches(Object *ob)
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
- if (me->bb) {
+ if (me && me->bb) {
me->bb->flag |= BOUNDBOX_DIRTY;
}
}
else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
Curve *cu = ob->data;
- if (cu->bb) {
+ if (cu && cu->bb) {
cu->bb->flag |= BOUNDBOX_DIRTY;
}
}
@@ -393,77 +393,52 @@ void BKE_object_free_caches(Object *object)
}
}
-/* do not free object itself */
-void BKE_object_free_ex(Object *ob, bool do_id_user)
+/** Free (or release) any data used by this object (does not free the object itself). */
+void BKE_object_free(Object *ob)
{
- int a;
-
+ BKE_animdata_free((ID *)ob, false);
+
BKE_object_free_modifiers(ob);
-
- /* disconnect specific data, but not for lib data (might be indirect data, can get relinked) */
- if (ob->data) {
- ID *id = ob->data;
- id_us_min(id);
- if (id->us == 0 && id->lib == NULL) {
- switch (ob->type) {
- case OB_MESH:
- BKE_mesh_unlink((Mesh *)id);
- break;
- case OB_CURVE:
- BKE_curve_unlink((Curve *)id);
- break;
- case OB_MBALL:
- BKE_mball_unlink((MetaBall *)id);
- break;
- }
- }
- ob->data = NULL;
- }
- if (ob->mat) {
- for (a = 0; a < ob->totcol; a++) {
- if (ob->mat[a])
- id_us_min(&ob->mat[a]->id);
- }
- MEM_freeN(ob->mat);
+ MEM_SAFE_FREE(ob->mat);
+ MEM_SAFE_FREE(ob->matbits);
+ MEM_SAFE_FREE(ob->iuser);
+ MEM_SAFE_FREE(ob->bb);
+
+ BLI_freelistN(&ob->defbase);
+ if (ob->pose) {
+ BKE_pose_free_ex(ob->pose, false);
+ ob->pose = NULL;
}
- if (ob->matbits) MEM_freeN(ob->matbits);
- ob->mat = NULL;
- ob->matbits = NULL;
- if (ob->iuser) MEM_freeN(ob->iuser);
- ob->iuser = NULL;
- if (ob->bb) MEM_freeN(ob->bb);
- ob->bb = NULL;
- if (ob->adt) BKE_animdata_free((ID *)ob);
- if (ob->poselib)
- id_us_min(&ob->poselib->id);
- if (ob->gpd)
- id_us_min(&ob->gpd->id);
- if (ob->defbase.first)
- BLI_freelistN(&ob->defbase);
- if (ob->pose)
- BKE_pose_free_ex(ob->pose, do_id_user);
- if (ob->mpath)
+ if (ob->mpath) {
animviz_free_motionpath(ob->mpath);
+ ob->mpath = NULL;
+ }
BKE_bproperty_free_list(&ob->prop);
-
+
free_sensors(&ob->sensors);
free_controllers(&ob->controllers);
free_actuators(&ob->actuators);
- BKE_constraints_free_ex(&ob->constraints, do_id_user);
+ BKE_constraints_free_ex(&ob->constraints, false);
free_partdeflect(ob->pd);
BKE_rigidbody_free_object(ob);
BKE_rigidbody_free_constraint(ob);
- if (ob->soft) sbFree(ob->soft);
- if (ob->bsoft) bsbFree(ob->bsoft);
- if (ob->gpulamp.first) GPU_lamp_free(ob);
+ if (ob->soft) {
+ sbFree(ob->soft);
+ ob->soft = NULL;
+ }
+ if (ob->bsoft) {
+ bsbFree(ob->bsoft);
+ ob->bsoft = NULL;
+ }
+ GPU_lamp_free(ob);
BKE_sculptsession_free(ob);
- if (ob->pc_ids.first) BLI_freelistN(&ob->pc_ids);
+ BLI_freelistN(&ob->pc_ids);
BLI_freelistN(&ob->lodlevels);
@@ -473,398 +448,12 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
if (ob->curve_cache->path)
free_path(ob->curve_cache->path);
MEM_freeN(ob->curve_cache);
+ ob->curve_cache = NULL;
}
BKE_previewimg_free(&ob->preview);
}
-void BKE_object_free(Object *ob)
-{
- BKE_object_free_ex(ob, true);
-}
-
-static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin, int UNUSED(cd_flag))
-{
- Object *unlinkOb = userData;
-
- if (*obpoin == unlinkOb) {
- *obpoin = NULL;
- // XXX: should this just be OB_RECALC_DATA?
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
-}
-
-void BKE_object_unlink(Main *bmain, Object *ob)
-{
- Object *obt;
- Material *mat;
- World *wrld;
- bScreen *sc;
- Scene *sce;
- SceneRenderLayer *srl;
- FreestyleLineSet *lineset;
- bNodeTree *ntree;
- Curve *cu;
- Tex *tex;
- Group *group;
- Camera *camera;
- bConstraint *con;
- //bActionStrip *strip; // XXX animsys
- ModifierData *md;
- ARegion *ar;
- RegionView3D *rv3d;
- LodLevel *lod;
- int a, found;
-
- unlink_controllers(&ob->controllers);
- unlink_actuators(&ob->actuators);
-
- /* check all objects: parents en bevels and fields, also from libraries */
- /* FIXME: need to check all animation blocks (drivers) */
- obt = bmain->object.first;
- while (obt) {
- if (obt->proxy == ob)
- obt->proxy = NULL;
- if (obt->proxy_from == ob) {
- obt->proxy_from = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB);
- }
- if (obt->proxy_group == ob)
- obt->proxy_group = NULL;
-
- if (obt->parent == ob) {
- obt->parent = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
-
- modifiers_foreachObjectLink(obt, unlink_object__unlinkModifierLinks, ob);
-
- if (ELEM(obt->type, OB_CURVE, OB_FONT)) {
- cu = obt->data;
-
- if (cu->bevobj == ob) {
- cu->bevobj = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
- if (cu->taperobj == ob) {
- cu->taperobj = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
- if (cu->textoncurve == ob) {
- cu->textoncurve = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- }
- }
- else if (obt->type == OB_ARMATURE && obt->pose) {
- bPoseChannel *pchan;
- for (pchan = obt->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == ob) {
- ct->tar = NULL;
- ct->subtarget[0] = '\0';
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- if (pchan->custom == ob)
- pchan->custom = NULL;
- }
- }
- else if (ELEM(OB_MBALL, ob->type, obt->type)) {
- if (BKE_mball_is_basis_for(obt, ob))
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
-
- sca_remove_ob_poin(obt, ob);
-
- for (con = obt->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == ob) {
- ct->tar = NULL;
- ct->subtarget[0] = '\0';
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
-
- /* object is deflector or field */
- if (ob->pd) {
- if (obt->soft)
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
-
- /* cloth */
- for (md = obt->modifiers.first; md; md = md->next)
- if (md->type == eModifierType_Cloth)
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
-
- /* strips */
-#if 0 // XXX old animation system
- for (strip = obt->nlastrips.first; strip; strip = strip->next) {
- if (strip->object == ob)
- strip->object = NULL;
-
- if (strip->modifiers.first) {
- bActionModifier *amod;
- for (amod = strip->modifiers.first; amod; amod = amod->next)
- if (amod->ob == ob)
- amod->ob = NULL;
- }
- }
-#endif // XXX old animation system
-
- /* particle systems */
- if (obt->particlesystem.first) {
- ParticleSystem *tpsys = obt->particlesystem.first;
- for (; tpsys; tpsys = tpsys->next) {
- BoidState *state = NULL;
- BoidRule *rule = NULL;
-
- ParticleTarget *pt = tpsys->targets.first;
- for (; pt; pt = pt->next) {
- if (pt->ob == ob) {
- pt->ob = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- break;
- }
- }
-
- if (tpsys->target_ob == ob) {
- tpsys->target_ob = NULL;
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
-
- if (tpsys->part->dup_ob == ob)
- tpsys->part->dup_ob = NULL;
-
- if (tpsys->part->phystype == PART_PHYS_BOIDS) {
- ParticleData *pa;
- BoidParticle *bpa;
- int p;
-
- for (p = 0, pa = tpsys->particles; p < tpsys->totpart; p++, pa++) {
- bpa = pa->boid;
- if (bpa->ground == ob)
- bpa->ground = NULL;
- }
- }
- if (tpsys->part->boids) {
- for (state = tpsys->part->boids->states.first; state; state = state->next) {
- for (rule = state->rules.first; rule; rule = rule->next) {
- if (rule->type == eBoidRuleType_Avoid) {
- BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
- if (gabr->ob == ob)
- gabr->ob = NULL;
- }
- else if (rule->type == eBoidRuleType_FollowLeader) {
- BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
- if (flbr->ob == ob)
- flbr->ob = NULL;
- }
- }
- }
- }
-
- if (tpsys->parent == ob)
- tpsys->parent = NULL;
- }
- if (ob->pd)
- DAG_id_tag_update(&obt->id, OB_RECALC_DATA);
- }
-
- /* levels of detail */
- for (lod = obt->lodlevels.first; lod; lod = lod->next) {
- if (lod->source == ob)
- lod->source = NULL;
- }
-
- obt = obt->id.next;
- }
-
- /* materials */
- for (mat = bmain->mat.first; mat; mat = mat->id.next) {
- if (mat->nodetree) {
- ntreeSwitchID(mat->nodetree, &ob->id, NULL);
- }
- for (a = 0; a < MAX_MTEX; a++) {
- if (mat->mtex[a] && ob == mat->mtex[a]->object) {
- /* actually, test for lib here... to do */
- mat->mtex[a]->object = NULL;
- }
- }
- }
-
- /* node trees */
- for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) {
- if (ntree->type == NTREE_SHADER)
- ntreeSwitchID(ntree, &ob->id, NULL);
- }
-
- /* textures */
- for (tex = bmain->tex.first; tex; tex = tex->id.next) {
- if (tex->env && (ob == tex->env->object)) tex->env->object = NULL;
- if (tex->pd && (ob == tex->pd->object)) tex->pd->object = NULL;
- if (tex->vd && (ob == tex->vd->object)) tex->vd->object = NULL;
- }
-
- /* worlds */
- wrld = bmain->world.first;
- while (wrld) {
- if (wrld->id.lib == NULL) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a] && ob == wrld->mtex[a]->object)
- wrld->mtex[a]->object = NULL;
- }
- }
-
- wrld = wrld->id.next;
- }
-
- /* scenes */
- sce = bmain->scene.first;
- while (sce) {
- if (sce->id.lib == NULL) {
- if (sce->camera == ob) sce->camera = NULL;
- if (sce->toolsettings->skgen_template == ob) sce->toolsettings->skgen_template = NULL;
- if (sce->toolsettings->particle.object == ob) sce->toolsettings->particle.object = NULL;
- if (sce->toolsettings->particle.shape_object == ob) sce->toolsettings->particle.shape_object = NULL;
-
-#ifdef DURIAN_CAMERA_SWITCH
- {
- TimeMarker *m;
-
- for (m = sce->markers.first; m; m = m->next) {
- if (m->camera == ob)
- m->camera = NULL;
- }
- }
-#endif
- if (sce->ed) {
- Sequence *seq;
- SEQ_BEGIN(sce->ed, seq)
- {
- if (seq->scene_camera == ob) {
- seq->scene_camera = NULL;
- }
- }
- SEQ_END
- }
-
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- for (lineset = (FreestyleLineSet *)srl->freestyleConfig.linesets.first;
- lineset; lineset = lineset->next)
- {
- if (lineset->linestyle) {
- BKE_linestyle_target_object_unlink(lineset->linestyle, ob);
- }
- }
- }
- }
-
- sce = sce->id.next;
- }
-
- /* screens */
- sc = bmain->screen.first;
- while (sc) {
- ScrArea *sa = sc->areabase.first;
- while (sa) {
- SpaceLink *sl;
-
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *) sl;
-
- /* found doesn't need to be set here */
- if (v3d->ob_centre == ob) {
- v3d->ob_centre = NULL;
- v3d->ob_centre_bone[0] = '\0';
- }
- if (v3d->localvd && v3d->localvd->ob_centre == ob) {
- v3d->localvd->ob_centre = NULL;
- v3d->localvd->ob_centre_bone[0] = '\0';
- }
-
- found = 0;
- if (v3d->camera == ob) {
- v3d->camera = NULL;
- found = 1;
- }
- if (v3d->localvd && v3d->localvd->camera == ob) {
- v3d->localvd->camera = NULL;
- found += 2;
- }
-
- if (found) {
- if (sa->spacetype == SPACE_VIEW3D) {
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- rv3d = (RegionView3D *)ar->regiondata;
- if (found == 1 || found == 3) {
- if (rv3d->persp == RV3D_CAMOB)
- rv3d->persp = RV3D_PERSP;
- }
- if (found == 2 || found == 3) {
- if (rv3d->localvd && rv3d->localvd->persp == RV3D_CAMOB)
- rv3d->localvd->persp = RV3D_PERSP;
- }
- }
- }
- }
- }
- }
-#if 0
- else if (ELEM(sl->spacetype, SPACE_OUTLINER, SPACE_BUTS, SPACE_NODE)) {
- /* now handled by WM_main_remove_editor_id_reference */
- }
-#endif
- }
-
- sa = sa->next;
- }
- sc = sc->id.next;
- }
-
- /* groups */
- group = bmain->group.first;
- while (group) {
- BKE_group_object_unlink(group, ob, NULL, NULL);
- group = group->id.next;
- }
-
- /* cameras */
- camera = bmain->camera.first;
- while (camera) {
- if (camera->dof_ob == ob) {
- camera->dof_ob = NULL;
- }
- camera = camera->id.next;
- }
-}
-
/* actual check for internal data, not context or flags */
bool BKE_object_is_in_editmode(Object *ob)
{
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 3a2663c5d48..8c1502643c5 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -298,13 +298,11 @@ void BKE_paint_brush_set(Paint *p, Brush *br)
}
}
+/** Free (or release) any data used by this paint curve (does not free the pcurve itself). */
void BKE_paint_curve_free(PaintCurve *pc)
{
- if (pc->points) {
- MEM_freeN(pc->points);
- pc->points = NULL;
- pc->tot_points = 0;
- }
+ MEM_SAFE_FREE(pc->points);
+ pc->tot_points = 0;
}
PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name)
@@ -378,6 +376,7 @@ Palette *BKE_palette_add(Main *bmain, const char *name)
return palette;
}
+/** Free (or release) any data used by this palette (does not free the palette itself). */
void BKE_palette_free(Palette *palette)
{
BLI_freelistN(&palette->colors);
@@ -493,8 +492,6 @@ void BKE_paint_init(Scene *sce, PaintMode mode, const char col[3])
void BKE_paint_free(Paint *paint)
{
- id_us_min((ID *)paint->brush);
- id_us_min((ID *)paint->palette);
curvemapping_free(paint->cavity_curve);
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 25dd7fff380..633227d68f3 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -376,12 +376,17 @@ static void fluid_free_settings(SPHFluidSettings *fluid)
MEM_freeN(fluid);
}
+/** Free (or release) any data used by this particle settings (does not free the partsett itself). */
void BKE_particlesettings_free(ParticleSettings *part)
{
- MTex *mtex;
int a;
- BKE_animdata_free(&part->id);
+
+ BKE_animdata_free((ID *)part, false);
+ for (a = 0; a < MAX_MTEX; a++) {
+ MEM_SAFE_FREE(part->mtex[a]);
+ }
+
if (part->clumpcurve)
curvemapping_free(part->clumpcurve);
if (part->roughcurve)
@@ -390,21 +395,12 @@ void BKE_particlesettings_free(ParticleSettings *part)
free_partdeflect(part->pd);
free_partdeflect(part->pd2);
- if (part->effector_weights)
- MEM_freeN(part->effector_weights);
+ MEM_SAFE_FREE(part->effector_weights);
BLI_freelistN(&part->dupliweights);
boid_free_settings(part->boids);
fluid_free_settings(part->fluid);
-
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = part->mtex[a];
- if (mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
- }
}
void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics)
@@ -573,10 +569,7 @@ void psys_free(Object *ob, ParticleSystem *psys)
if (!nr)
ob->transflag &= ~OB_DUPLIPARTS;
- if (psys->part) {
- id_us_min(&psys->part->id);
- psys->part = NULL;
- }
+ psys->part = NULL;
BKE_ptcache_free_list(&psys->ptcaches);
psys->pointcache = NULL;
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
index e90a39e8c0e..a468420f87d 100644
--- a/source/blender/blenkernel/intern/sca.c
+++ b/source/blender/blenkernel/intern/sca.c
@@ -653,77 +653,6 @@ void set_sca_new_poins(void)
}
}
-void sca_remove_ob_poin(Object *obt, Object *ob)
-{
- bSensor *sens;
- bMessageSensor *ms;
- bActuator *act;
- bCameraActuator *ca;
- bObjectActuator *oa;
- bSceneActuator *sa;
- bEditObjectActuator *eoa;
- bPropertyActuator *pa;
- bMessageActuator *ma;
- bParentActuator *para;
- bArmatureActuator *aa;
- bSteeringActuator *sta;
-
-
- sens= obt->sensors.first;
- while (sens) {
- switch (sens->type) {
- case SENS_MESSAGE:
- ms= sens->data;
- if (ms->fromObject==ob) ms->fromObject= NULL;
- }
- sens= sens->next;
- }
-
- act= obt->actuators.first;
- while (act) {
- switch (act->type) {
- case ACT_CAMERA:
- ca= act->data;
- if (ca->ob==ob) ca->ob= NULL;
- break;
- case ACT_OBJECT:
- oa= act->data;
- if (oa->reference==ob) oa->reference= NULL;
- break;
- case ACT_PROPERTY:
- pa= act->data;
- if (pa->ob==ob) pa->ob= NULL;
- break;
- case ACT_SCENE:
- sa= act->data;
- if (sa->camera==ob) sa->camera= NULL;
- break;
- case ACT_EDIT_OBJECT:
- eoa= act->data;
- if (eoa->ob==ob) eoa->ob= NULL;
- break;
- case ACT_MESSAGE:
- ma= act->data;
- if (ma->toObject==ob) ma->toObject= NULL;
- break;
- case ACT_PARENT:
- para = act->data;
- if (para->ob==ob) para->ob = NULL;
- break;
- case ACT_ARMATURE:
- aa = act->data;
- if (aa->target == ob) aa->target = NULL;
- if (aa->subtarget == ob) aa->subtarget = NULL;
- break;
- case ACT_STEERING:
- sta = act->data;
- if (sta->navmesh == ob) sta->navmesh = NULL;
- if (sta->target == ob) sta->target = NULL;
- }
- act= act->next;
- }
-}
-
/* ******************** INTERFACE ******************* */
void sca_move_sensor(bSensor *sens_to_move, Object *ob, int move_up)
{
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index a3393b6b9c0..0e8efca04d0 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -357,41 +357,34 @@ void BKE_scene_groups_relink(Scene *sce)
BKE_rigidbody_world_groups_relink(sce->rigidbody_world);
}
-/* do not free scene itself */
+/** Free (or release) any data used by this scene (does not free the scene itself). */
void BKE_scene_free(Scene *sce)
{
- Base *base;
SceneRenderLayer *srl;
+ BKE_animdata_free((ID *)sce, false);
+
/* check all sequences */
BKE_sequencer_clear_scene_in_allseqs(G.main, sce);
- base = sce->base.first;
- while (base) {
- id_us_min(&base->object->id);
- base = base->next;
- }
- /* do not free objects! */
-
- if (sce->gpd) {
-#if 0 /* removed since this can be invalid memory when freeing everything */
- /* since the grease pencil data is freed before the scene.
- * since grease pencil data is not (yet?), shared between objects
- * its probably safe not to do this, some save and reload will free this. */
- id_us_min(&sce->gpd->id);
-#endif
- sce->gpd = NULL;
- }
-
+ sce->basact = NULL;
BLI_freelistN(&sce->base);
BKE_sequencer_editing_free(sce);
- BKE_animdata_free((ID *)sce);
BKE_keyingsets_free(&sce->keyingsets);
-
- if (sce->rigidbody_world)
+
+ /* is no lib link block, but scene extension */
+ if (sce->nodetree) {
+ ntreeFreeTree(sce->nodetree);
+ MEM_freeN(sce->nodetree);
+ sce->nodetree = NULL;
+ }
+
+ if (sce->rigidbody_world) {
BKE_rigidbody_free_world(sce->rigidbody_world);
-
+ sce->rigidbody_world = NULL;
+ }
+
if (sce->r.avicodecdata) {
free_avicodecdata(sce->r.avicodecdata);
MEM_freeN(sce->r.avicodecdata);
@@ -444,15 +437,8 @@ void BKE_scene_free(Scene *sce)
if (sce->depsgraph)
DEG_graph_free(sce->depsgraph);
- if (sce->nodetree) {
- ntreeFreeTree(sce->nodetree);
- MEM_freeN(sce->nodetree);
- }
-
- if (sce->stats)
- MEM_freeN(sce->stats);
- if (sce->fps_info)
- MEM_freeN(sce->fps_info);
+ MEM_SAFE_FREE(sce->stats);
+ MEM_SAFE_FREE(sce->fps_info);
BKE_sound_destroy_scene(sce);
@@ -904,40 +890,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
return NULL;
}
-void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce)
-{
- Scene *sce1;
- bScreen *screen;
-
- /* check all sets */
- for (sce1 = bmain->scene.first; sce1; sce1 = sce1->id.next)
- if (sce1->set == sce)
- sce1->set = NULL;
-
- for (sce1 = bmain->scene.first; sce1; sce1 = sce1->id.next) {
- bNode *node;
-
- if (sce1 == sce || !sce1->nodetree)
- continue;
-
- for (node = sce1->nodetree->nodes.first; node; node = node->next) {
- if (node->id == &sce->id)
- node->id = NULL;
- }
- }
-
- /* all screens */
- for (screen = bmain->screen.first; screen; screen = screen->id.next) {
- if (screen->scene == sce) {
- screen->scene = newsce;
- }
-
- /* editors are handled by WM_main_remove_editor_id_reference */
- }
-
- BKE_libblock_free(bmain, sce);
-}
-
/* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */
int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter,
Scene **scene, int val, Base **base, Object **ob)
@@ -1193,6 +1145,8 @@ void BKE_scene_base_unlink(Scene *sce, Base *base)
BKE_rigidbody_remove_object(sce, base->object);
BLI_remlink(&sce->base, base);
+ if (sce->basact == base)
+ sce->basact = NULL;
}
void BKE_scene_base_deselect_all(Scene *sce)
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 139c6670f74..857bd5447c8 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -273,17 +273,18 @@ void BKE_spacedata_draw_locks(int set)
}
}
-static void (*spacedata_id_unref_cb)(struct SpaceLink *sl, const struct ID *id) = NULL;
+static void (*spacedata_id_remap_cb)(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id) = NULL;
-void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *))
+void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *sa, SpaceLink *sl, ID *, ID *))
{
- spacedata_id_unref_cb = func;
+ spacedata_id_remap_cb = func;
}
-void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id)
+/* UNUSED!!! */
+void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id)
{
- if (spacedata_id_unref_cb) {
- spacedata_id_unref_cb(sl, id);
+ if (spacedata_id_remap_cb) {
+ spacedata_id_remap_cb(sa, sl, id, NULL);
}
}
@@ -358,11 +359,13 @@ void BKE_screen_area_free(ScrArea *sa)
BLI_freelistN(&sa->actionzones);
}
-/* don't free screen itself */
+/** Free (or release) any data used by this screen (does not free the screen itself). */
void BKE_screen_free(bScreen *sc)
{
ScrArea *sa, *san;
ARegion *ar;
+
+ /* No animdata here. */
for (ar = sc->regionbase.first; ar; ar = ar->next)
BKE_area_region_free(NULL, ar);
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index c82f3a3af23..5ef502e0182 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -3092,7 +3092,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
BKE_maskrasterize_handle_init(mr_handle, mask_temp, context->rectx, context->recty, true, true, true);
- BKE_mask_free_nolib(mask_temp);
+ BKE_mask_free(mask_temp);
MEM_freeN(mask_temp);
BKE_maskrasterize_buffer(mr_handle, context->rectx, context->recty, maskbuf);
@@ -5154,7 +5154,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
- BKE_sound_delete(bmain, sound);
+ BKE_libblock_free(bmain, sound);
#if 0
if (op)
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index b016f8a49ed..414be73e234 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -123,8 +123,11 @@ bSound *BKE_sound_new_file_exists(struct Main *bmain, const char *filepath)
return BKE_sound_new_file_exists_ex(bmain, filepath, NULL);
}
+/** Free (or release) any data used by this sound (does not free the sound itself). */
void BKE_sound_free(bSound *sound)
{
+ /* No animdata here. */
+
if (sound->packedfile) {
freePackedFile(sound->packedfile);
sound->packedfile = NULL;
@@ -148,8 +151,7 @@ void BKE_sound_free(bSound *sound)
BLI_spin_end(sound->spinlock);
MEM_freeN(sound->spinlock);
sound->spinlock = NULL;
- }
-
+ }
#endif /* WITH_AUDASPACE */
}
@@ -315,15 +317,6 @@ bSound *BKE_sound_new_limiter(struct Main *bmain, bSound *source, float start, f
}
#endif
-void BKE_sound_delete(struct Main *bmain, bSound *sound)
-{
- if (sound) {
- BKE_sound_free(sound);
-
- BKE_libblock_free(bmain, sound);
- }
-}
-
void BKE_sound_cache(bSound *sound)
{
sound->flags |= SOUND_FLAGS_CACHING;
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index c452065fbad..e5075a2d382 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -141,8 +141,5 @@ void BKE_speaker_make_local(Speaker *spk)
void BKE_speaker_free(Speaker *spk)
{
- if (spk->sound)
- id_us_min(&spk->sound->id);
-
- BKE_animdata_free((ID *)spk);
+ BKE_animdata_free((ID *)spk, false);
}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 6def9e3e503..594f9dffbee 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -171,14 +171,17 @@ void BKE_text_free_lines(Text *text)
text->curl = text->sell = NULL;
}
+/** Free (or release) any data used by this text (does not free the text itself). */
void BKE_text_free(Text *text)
{
+ /* No animdata here. */
+
BKE_text_free_lines(text);
- if (text->name) MEM_freeN(text->name);
- MEM_freeN(text->undo_buf);
+ MEM_SAFE_FREE(text->name);
+ MEM_SAFE_FREE(text->undo_buf);
#ifdef WITH_PYTHON
- if (text->compiled) BPY_text_free_code(text);
+ BPY_text_free_code(text);
#endif
}
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index d353042b711..9326ece7a4b 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -557,23 +557,38 @@ int colorband_element_remove(struct ColorBand *coba, int index)
/* ******************* TEX ************************ */
+/** Free (or release) any data used by this texture (does not free the texure itself). */
void BKE_texture_free(Tex *tex)
{
- if (tex->coba) MEM_freeN(tex->coba);
- if (tex->env) BKE_texture_envmap_free(tex->env);
- if (tex->pd) BKE_texture_pointdensity_free(tex->pd);
- if (tex->vd) BKE_texture_voxeldata_free(tex->vd);
- if (tex->ot) BKE_texture_ocean_free(tex->ot);
- BKE_animdata_free((struct ID *)tex);
-
- BKE_previewimg_free(&tex->preview);
- BKE_icon_id_delete((struct ID *)tex);
- tex->id.icon_id = 0;
-
+ BKE_animdata_free((ID *)tex, false);
+
+ /* is no lib link block, but texture extension */
if (tex->nodetree) {
ntreeFreeTree(tex->nodetree);
MEM_freeN(tex->nodetree);
+ tex->nodetree = NULL;
}
+
+ MEM_SAFE_FREE(tex->coba);
+ if (tex->env) {
+ BKE_texture_envmap_free(tex->env);
+ tex->env = NULL;
+ }
+ if (tex->pd) {
+ BKE_texture_pointdensity_free(tex->pd);
+ tex->pd = NULL;
+ }
+ if (tex->vd) {
+ BKE_texture_voxeldata_free(tex->vd);
+ tex->vd = NULL;
+ }
+ if (tex->ot) {
+ BKE_texture_ocean_free(tex->ot);
+ tex->ot = NULL;
+ }
+
+ BKE_icon_id_delete((ID *)tex);
+ BKE_previewimg_free(&tex->preview);
}
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 17a2e7f14fd..ec021586be5 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -52,38 +52,28 @@
#include "GPU_material.h"
-void BKE_world_free_ex(World *wrld, bool do_id_user)
+/** Free (or release) any data used by this world (does not free the world itself). */
+void BKE_world_free(World *wrld)
{
- MTex *mtex;
int a;
-
+
+ BKE_animdata_free((ID *)wrld, false);
+
for (a = 0; a < MAX_MTEX; a++) {
- mtex = wrld->mtex[a];
- if (do_id_user && mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
+ MEM_SAFE_FREE(wrld->mtex[a]);
}
- BKE_previewimg_free(&wrld->preview);
-
- BKE_animdata_free((ID *)wrld);
/* is no lib link block, but world extension */
if (wrld->nodetree) {
- ntreeFreeTree_ex(wrld->nodetree, do_id_user);
+ ntreeFreeTree(wrld->nodetree);
MEM_freeN(wrld->nodetree);
+ wrld->nodetree = NULL;
}
- if (wrld->gpumaterial.first)
- GPU_material_free(&wrld->gpumaterial);
+ GPU_material_free(&wrld->gpumaterial);
BKE_icon_id_delete((struct ID *)wrld);
- wrld->id.icon_id = 0;
-}
-
-void BKE_world_free(World *wrld)
-{
- BKE_world_free_ex(wrld, true);
+ BKE_previewimg_free(&wrld->preview);
}
void BKE_world_init(World *wrld)