forked from bartvdbraak/blender
Fix T37599: Crash making linked objects local and undo
Root of the issues comes to the fact that it's possible to produce a situation when library object data uses local object. This is actually forbidden and not supported by .blend IO. Made it so Make Local wouldn't produce such an unsupported states. Reviewers: brecht Differential Revision: https://developer.blender.org/D372
This commit is contained in:
parent
97cb76a45d
commit
6e5e3b73f3
57
source/blender/blenkernel/BKE_library_query.h
Normal file
57
source/blender/blenkernel/BKE_library_query.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* ***** 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2014 by Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Sergey SHarybin.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
#ifndef __BKE_LIBRARY_QUERY_H__
|
||||
#define __BKE_LIBRARY_QUERY_H__
|
||||
|
||||
/** \file BKE_library_query.h
|
||||
* \ingroup bke
|
||||
* \since March 2014
|
||||
* \author sergey
|
||||
*/
|
||||
|
||||
struct ID;
|
||||
|
||||
/* Tips for the callback for cases it's gonna to modify the pointer. */
|
||||
enum {
|
||||
IDWALK_NOP = 0,
|
||||
IDWALK_NEVER_NULL = (1 << 0),
|
||||
IDWALK_NEVER_SELF = (1 << 1),
|
||||
};
|
||||
|
||||
/* Call a callback for each ID link which the given ID uses.
|
||||
*
|
||||
* Return 'false' if you want to stop iteration.
|
||||
*/
|
||||
typedef bool (*LibraryIDLinkCallback) (void *user_data, struct ID **id_pointer, int cd_flag);
|
||||
|
||||
/* Flags for the foreach function itself. */
|
||||
enum {
|
||||
IDWALK_READONLY = (1 << 0),
|
||||
};
|
||||
|
||||
/* Loop over all of the ID's this datablock links to. */
|
||||
void BKE_library_foreach_ID_link(struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
|
||||
|
||||
#endif /* __BKE_LIBRARY_QUERY_H__ */
|
@ -107,6 +107,7 @@ set(SRC
|
||||
intern/lamp.c
|
||||
intern/lattice.c
|
||||
intern/library.c
|
||||
intern/library_query.c
|
||||
intern/linestyle.c
|
||||
intern/mask.c
|
||||
intern/mask_evaluate.c
|
||||
@ -214,6 +215,7 @@ set(SRC
|
||||
BKE_lamp.h
|
||||
BKE_lattice.h
|
||||
BKE_library.h
|
||||
BKE_library_query.h
|
||||
BKE_linestyle.h
|
||||
BKE_main.h
|
||||
BKE_mask.h
|
||||
|
460
source/blender/blenkernel/intern/library_query.c
Normal file
460
source/blender/blenkernel/intern/library_query.c
Normal file
@ -0,0 +1,460 @@
|
||||
/*
|
||||
* ***** 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2014 by Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Sergey Sharybin.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/blenkernel/intern/library_query.c
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_group_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_lamp_types.h"
|
||||
#include "DNA_lattice_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_force.h"
|
||||
#include "DNA_sequence_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_speaker_types.h"
|
||||
#include "DNA_sound_types.h"
|
||||
#include "DNA_vfont_types.h"
|
||||
#include "DNA_world_types.h"
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_library_query.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_particle.h"
|
||||
#include "BKE_sequencer.h"
|
||||
#include "BKE_tracking.h"
|
||||
|
||||
#define FOREACH_CALLBACK_INVOKE_ID_PP(self_id, id_pp, flag, callback, user_data, cb_flag) \
|
||||
{ \
|
||||
ID *old_id = *id_pp; \
|
||||
bool keep_working = callback(user_data, id_pp, cb_flag); \
|
||||
if (flag & IDWALK_READONLY) { \
|
||||
BLI_assert(*id_pp == old_id); \
|
||||
} \
|
||||
if (keep_working == false) { \
|
||||
/* REAL DANGER! Beware of this return! */ \
|
||||
/* TODO(sergey): Make it less creepy without too much duplicated code.. */ \
|
||||
return; \
|
||||
} \
|
||||
} (void) 0
|
||||
|
||||
#define FOREACH_CALLBACK_INVOKE_ID(self_id, id, flag, callback, user_data, cb_flag) \
|
||||
FOREACH_CALLBACK_INVOKE_ID_PP(self_id, &(id), flag, callback, user_data, cb_flag) \
|
||||
|
||||
#define FOREACH_CALLBACK_INVOKE(self_id, id_super, flag, callback, user_data, cb_flag) \
|
||||
{ \
|
||||
CHECK_TYPE(&((id_super)->id), ID *); \
|
||||
FOREACH_CALLBACK_INVOKE_ID_PP(self_id, (ID **)&id_super, flag, callback, user_data, cb_flag); \
|
||||
} (void) 0
|
||||
|
||||
typedef struct LibraryForeachIDData {
|
||||
ID *self_id;
|
||||
int flag;
|
||||
LibraryIDLinkCallback callback;
|
||||
void *user_data;
|
||||
} LibraryForeachIDData;
|
||||
|
||||
static void library_foreach_modifiersForeachIDLink(void *user_data, Object *UNUSED(object),
|
||||
ID **id_pointer)
|
||||
{
|
||||
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
|
||||
FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, IDWALK_NOP);
|
||||
}
|
||||
|
||||
static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID **id_pointer,
|
||||
short UNUSED(isReference), void *user_data)
|
||||
{
|
||||
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
|
||||
FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, IDWALK_NOP);
|
||||
}
|
||||
|
||||
static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt)
|
||||
{
|
||||
FCurve *fcu;
|
||||
|
||||
for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
|
||||
ChannelDriver *driver = fcu->driver;
|
||||
DriverVar *dvar;
|
||||
|
||||
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
|
||||
/* only used targets */
|
||||
DRIVER_TARGETS_USED_LOOPER(dvar)
|
||||
{
|
||||
FOREACH_CALLBACK_INVOKE_ID(data->self_id, dtar->id, data->flag, data->callback, data->user_data, IDWALK_NOP);
|
||||
}
|
||||
DRIVER_TARGETS_LOOPER_END
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
|
||||
{
|
||||
FOREACH_CALLBACK_INVOKE(data->self_id, mtex->object, data->flag, data->callback, data->user_data, IDWALK_NOP);
|
||||
FOREACH_CALLBACK_INVOKE(data->self_id, mtex->tex, data->flag, data->callback, data->user_data, IDWALK_NOP);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loop over all of the ID's this datablock links to.
|
||||
*
|
||||
* \note: May be extended to be recursive in the future.
|
||||
*/
|
||||
void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
|
||||
{
|
||||
AnimData *adt;
|
||||
LibraryForeachIDData data;
|
||||
int i;
|
||||
|
||||
data.self_id = id;
|
||||
data.flag = flag;
|
||||
data.callback = callback;
|
||||
data.user_data = user_data;
|
||||
|
||||
adt = BKE_animdata_from_id(id);
|
||||
if (adt) {
|
||||
library_foreach_animationData(&data, adt);
|
||||
}
|
||||
|
||||
#define CALLBACK_INVOKE_ID(check_id, cb_flag) \
|
||||
FOREACH_CALLBACK_INVOKE_ID(id, check_id, flag, callback, user_data, cb_flag)
|
||||
|
||||
#define CALLBACK_INVOKE(check_id_super, cb_flag) \
|
||||
FOREACH_CALLBACK_INVOKE(id, check_id_super, flag, callback, user_data, cb_flag)
|
||||
|
||||
switch (GS(id->name)) {
|
||||
case ID_SCE:
|
||||
{
|
||||
Scene *scene = (Scene *) id;
|
||||
Base *base;
|
||||
|
||||
CALLBACK_INVOKE(scene->camera, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(scene->world, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(scene->set, IDWALK_NOP);
|
||||
if (scene->basact) {
|
||||
CALLBACK_INVOKE(scene->basact->object, IDWALK_NOP);
|
||||
}
|
||||
CALLBACK_INVOKE(scene->obedit, IDWALK_NOP);
|
||||
|
||||
if (scene->ed) {
|
||||
Sequence *seq;
|
||||
SEQP_BEGIN(scene->ed, seq)
|
||||
{
|
||||
CALLBACK_INVOKE(seq->scene, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(seq->scene_camera, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(seq->clip, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(seq->mask, IDWALK_NOP);
|
||||
}
|
||||
SEQ_END
|
||||
}
|
||||
|
||||
CALLBACK_INVOKE(scene->gpd, IDWALK_NOP);
|
||||
|
||||
for (base = scene->base.first; base; base = base->next) {
|
||||
CALLBACK_INVOKE(base->object, IDWALK_NOP);
|
||||
}
|
||||
}
|
||||
|
||||
case ID_OB:
|
||||
{
|
||||
Object *object = (Object *) id;
|
||||
CALLBACK_INVOKE(object->parent, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(object->track, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(object->proxy, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(object->poselib, IDWALK_NOP);
|
||||
for (i = 0; i < object->totcol; i++) {
|
||||
CALLBACK_INVOKE(object->mat[i], IDWALK_NOP);
|
||||
}
|
||||
CALLBACK_INVOKE(object->gpd, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(object->dup_group, IDWALK_NOP);
|
||||
if (object->particlesystem.first) {
|
||||
ParticleSystem *particle_system;
|
||||
for (particle_system = object->particlesystem.first;
|
||||
particle_system;
|
||||
particle_system = particle_system->next)
|
||||
{
|
||||
CALLBACK_INVOKE(particle_system->target_ob, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(particle_system->parent, IDWALK_NOP);
|
||||
}
|
||||
}
|
||||
|
||||
if (object->pose) {
|
||||
bPoseChannel *pose_channel;
|
||||
for (pose_channel = object->pose->chanbase.first;
|
||||
pose_channel;
|
||||
pose_channel = pose_channel->next)
|
||||
{
|
||||
CALLBACK_INVOKE(pose_channel->custom, IDWALK_NOP);
|
||||
BKE_id_loop_constraints(&pose_channel->constraints,
|
||||
library_foreach_constraintObjectLooper,
|
||||
&data);
|
||||
}
|
||||
}
|
||||
|
||||
modifiers_foreachIDLink(object,
|
||||
library_foreach_modifiersForeachIDLink,
|
||||
&data);
|
||||
BKE_id_loop_constraints(&object->constraints,
|
||||
library_foreach_constraintObjectLooper,
|
||||
&data);
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_ME:
|
||||
{
|
||||
Mesh *mesh = (Mesh *) id;
|
||||
CALLBACK_INVOKE(mesh->texcomesh, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(mesh->key, IDWALK_NOP);
|
||||
for (i = 0; i < mesh->totcol; i++) {
|
||||
CALLBACK_INVOKE(mesh->mat[i], IDWALK_NOP);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_CU:
|
||||
{
|
||||
Curve *curve = (Curve *) id;
|
||||
CALLBACK_INVOKE(curve->bevobj, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(curve->taperobj, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(curve->textoncurve, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(curve->key, IDWALK_NOP);
|
||||
for (i = 0; i < curve->totcol; i++) {
|
||||
CALLBACK_INVOKE(curve->mat[i], IDWALK_NOP);
|
||||
}
|
||||
CALLBACK_INVOKE(curve->vfont, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(curve->vfontb, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(curve->vfonti, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(curve->vfontbi, IDWALK_NOP);
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_MB:
|
||||
{
|
||||
MetaBall *metaball = (MetaBall *) id;
|
||||
for (i = 0; i < metaball->totcol; i++) {
|
||||
CALLBACK_INVOKE(metaball->mat[i], IDWALK_NOP);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_MA:
|
||||
{
|
||||
Material *material = (Material *) id;
|
||||
for (i = 0; i < MAX_MTEX; i++) {
|
||||
if (material->mtex[i]) {
|
||||
library_foreach_mtex(&data, material->mtex[i]);
|
||||
}
|
||||
}
|
||||
CALLBACK_INVOKE(material->nodetree, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(material->group, IDWALK_NOP);
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_TE:
|
||||
{
|
||||
Tex *texture = (Tex *) id;
|
||||
CALLBACK_INVOKE(texture->nodetree, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(texture->ima, IDWALK_NOP);
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_LT:
|
||||
{
|
||||
Lattice *lattice = (Lattice *) id;
|
||||
CALLBACK_INVOKE(lattice->key, IDWALK_NOP);
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_LA:
|
||||
{
|
||||
Lamp *lamp = (Lamp *) id;
|
||||
for (i = 0; i < MAX_MTEX; i++) {
|
||||
if (lamp->mtex[i]) {
|
||||
library_foreach_mtex(&data, lamp->mtex[i]);
|
||||
}
|
||||
}
|
||||
CALLBACK_INVOKE(lamp->nodetree, IDWALK_NOP);
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_CA:
|
||||
{
|
||||
Camera *camera = (Camera *) id;
|
||||
CALLBACK_INVOKE(camera->dof_ob, IDWALK_NOP);
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_KE:
|
||||
{
|
||||
Key *key = (Key *) id;
|
||||
CALLBACK_INVOKE_ID(key->from, IDWALK_NOP);
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_SCR:
|
||||
{
|
||||
bScreen *screen = (bScreen *) id;
|
||||
CALLBACK_INVOKE(screen->scene, IDWALK_NOP);
|
||||
}
|
||||
|
||||
case ID_WO:
|
||||
{
|
||||
World *world = (World *) id;
|
||||
for (i = 0; i < MAX_MTEX; i++) {
|
||||
if (world->mtex[i]) {
|
||||
library_foreach_mtex(&data, world->mtex[i]);
|
||||
}
|
||||
}
|
||||
CALLBACK_INVOKE(world->nodetree, IDWALK_NOP);
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_SPK:
|
||||
{
|
||||
Speaker *speaker = (Speaker *) id;
|
||||
CALLBACK_INVOKE(speaker->sound, IDWALK_NOP);
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_GR:
|
||||
{
|
||||
Group *group = (Group *) id;
|
||||
GroupObject *group_object;
|
||||
for (group_object = group->gobject.first;
|
||||
group_object;
|
||||
group_object = group_object->next)
|
||||
{
|
||||
CALLBACK_INVOKE(group_object->ob, IDWALK_NOP);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_NT:
|
||||
{
|
||||
bNodeTree *ntree = (bNodeTree *) id;
|
||||
bNode *node;
|
||||
for (node = ntree->nodes.first; node; node = node->next) {
|
||||
CALLBACK_INVOKE_ID(node->id, IDWALK_NOP);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_BR:
|
||||
{
|
||||
Brush *brush = (Brush *) id;
|
||||
CALLBACK_INVOKE(brush->toggle_brush, IDWALK_NOP);
|
||||
library_foreach_mtex(&data, &brush->mtex);
|
||||
library_foreach_mtex(&data, &brush->mask_mtex);
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_PA:
|
||||
{
|
||||
ParticleSettings *particle_settings = (ParticleSettings *) id;
|
||||
CALLBACK_INVOKE(particle_settings->dup_group, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(particle_settings->dup_ob, IDWALK_NOP);
|
||||
CALLBACK_INVOKE(particle_settings->bb_ob, IDWALK_NOP);
|
||||
if (particle_settings->effector_weights) {
|
||||
CALLBACK_INVOKE(particle_settings->effector_weights->group, IDWALK_NOP);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_MC:
|
||||
{
|
||||
MovieClip *clip = (MovieClip *) id;
|
||||
MovieTracking *tracking = &clip->tracking;
|
||||
MovieTrackingObject *object;
|
||||
CALLBACK_INVOKE(clip->gpd, IDWALK_NOP);
|
||||
for (object = tracking->objects.first;
|
||||
object;
|
||||
object = object->next)
|
||||
{
|
||||
ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
|
||||
MovieTrackingTrack *track;
|
||||
for (track = tracksbase->first;
|
||||
track;
|
||||
track = track->next)
|
||||
{
|
||||
CALLBACK_INVOKE(track->gpd, IDWALK_NOP);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_MSK:
|
||||
{
|
||||
Mask *mask = (Mask *) id;
|
||||
MaskLayer *mask_layer;
|
||||
for (mask_layer = mask->masklayers.first;
|
||||
mask_layer;
|
||||
mask_layer = mask_layer->next)
|
||||
{
|
||||
MaskSpline *mask_spline;
|
||||
|
||||
CALLBACK_INVOKE_ID(mask_spline->parent.id, IDWALK_NOP);
|
||||
|
||||
for (mask_spline = mask_layer->splines.first;
|
||||
mask_spline;
|
||||
mask_spline = mask_spline->next)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < mask_spline->tot_point; i++) {
|
||||
MaskSplinePoint *point = &mask_spline->points[i];
|
||||
CALLBACK_INVOKE_ID(point->parent.id, IDWALK_NOP);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#undef CALLBACK_INVOKE_ID
|
||||
#undef CALLBACK_INVOKE
|
||||
}
|
||||
|
||||
#undef FOREACH_CALLBACK_INVOKE_ID
|
||||
#undef FOREACH_CALLBACK_INVOKE
|
@ -76,6 +76,7 @@
|
||||
#include "BKE_lamp.h"
|
||||
#include "BKE_lattice.h"
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_library_query.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_mball.h"
|
||||
@ -2080,6 +2081,56 @@ enum {
|
||||
MAKE_LOCAL_ALL
|
||||
};
|
||||
|
||||
static bool tag_localizable_looper(void *UNUSED(user_data), ID **id_pointer, int UNUSED(cd_flag))
|
||||
{
|
||||
if (*id_pointer) {
|
||||
(*id_pointer)->flag &= ~LIB_DOIT;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void tag_localizable_objects(bContext *C, int mode)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Object *object;
|
||||
|
||||
BKE_main_id_tag_all(bmain, false);
|
||||
|
||||
/* Set LIB_DOIT flag for all selected objects, so next we can check whether
|
||||
* object is gonna to become local or not.
|
||||
*/
|
||||
CTX_DATA_BEGIN (C, Object *, object, selected_objects)
|
||||
{
|
||||
object->id.flag |= LIB_DOIT;
|
||||
|
||||
/* If data is also gonna to become local, mark data we're interested in
|
||||
* as gonna-to-be-local.
|
||||
*/
|
||||
if (mode == MAKE_LOCAL_SELECT_OBDATA) {
|
||||
ID *data_id = (ID *) object->data;
|
||||
data_id->flag |= LIB_DOIT;
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
/* Also forbid making objects local if other library objects are using
|
||||
* them for modifiers or constraints.
|
||||
*/
|
||||
for (object = bmain->object.first; object; object = object->id.next) {
|
||||
if ((object->id.flag & LIB_DOIT) == 0) {
|
||||
BKE_library_foreach_ID_link(&object->id, tag_localizable_looper, NULL, IDWALK_READONLY);
|
||||
}
|
||||
if (object->data) {
|
||||
ID *data_id = (ID *) object->data;
|
||||
if ((data_id->flag & LIB_DOIT) == 0) {
|
||||
BKE_library_foreach_ID_link(data_id, tag_localizable_looper, NULL, IDWALK_READONLY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO(sergey): Drivers targets? */
|
||||
}
|
||||
|
||||
static int make_local_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
@ -2096,10 +2147,15 @@ static int make_local_exec(bContext *C, wmOperator *op)
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
tag_localizable_objects(C, mode);
|
||||
BKE_main_id_clear_newpoins(bmain);
|
||||
|
||||
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
|
||||
{
|
||||
if ((ob->id.flag & LIB_DOIT) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ob->id.lib)
|
||||
id_make_local(&ob->id, false);
|
||||
}
|
||||
@ -2116,6 +2172,10 @@ static int make_local_exec(bContext *C, wmOperator *op)
|
||||
|
||||
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
|
||||
{
|
||||
if ((ob->id.flag & LIB_DOIT) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
id = ob->data;
|
||||
|
||||
if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) {
|
||||
@ -2145,6 +2205,10 @@ static int make_local_exec(bContext *C, wmOperator *op)
|
||||
if (mode == MAKE_LOCAL_SELECT_OBDATA_MATERIAL) {
|
||||
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
|
||||
{
|
||||
if ((ob->id.flag & LIB_DOIT) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ob->type == OB_LAMP) {
|
||||
la = ob->data;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user