Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/object/object_group.c
| Context not available. | |||||
| /********************* 3d view operators ***********************/ | /********************* 3d view operators ***********************/ | ||||
| static bool group_link_early_exit_check(Group *group, Object *object) | |||||
| { | |||||
| GroupObject *group_object; | |||||
| for (group_object = group->gobject.first; group_object; group_object = group_object->next) { | |||||
| if (group_object->ob == object) { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static bool check_object_instances_group_recursive(Object *object, Group *group) | |||||
| { | |||||
| if (object->dup_group) { | |||||
| Group *dup_group = object->dup_group; | |||||
| if ((dup_group->id.flag & LIB_DOIT) == 0) { | |||||
| /* Cycle already exists in groups, let's prevent further crappyness */ | |||||
| return true; | |||||
| } | |||||
| /* flag the object to identify cyclic dependencies in further dupli groups */ | |||||
| dup_group->id.flag &= ~LIB_DOIT; | |||||
| if (dup_group == group) | |||||
| return true; | |||||
| else { | |||||
| GroupObject *gob; | |||||
| for (gob = dup_group->gobject.first; gob; gob = gob->next) { | |||||
| if (check_object_instances_group_recursive(gob->ob, group)) | |||||
| return true; | |||||
| } | |||||
| } | |||||
| /* un-flag the object, it's allowed to have the same group multiple times in parallel */ | |||||
| dup_group->id.flag |= LIB_DOIT; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /* can be called with C == NULL */ | /* can be called with C == NULL */ | ||||
| static EnumPropertyItem *group_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) | static EnumPropertyItem *group_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) | ||||
| { | { | ||||
| Context not available. | |||||
| CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) | CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) | ||||
| { | { | ||||
| if (group_link_early_exit_check(group, base->object)) | if (BKE_group_object_exists(group, base->object)) | ||||
| continue; | continue; | ||||
| if (!check_object_instances_group_recursive(base->object, group)) { | if (!BKE_group_dependency_cycles_check(base->object, group)) { | ||||
| BKE_group_object_add(group, base->object, scene, base); | BKE_group_object_add(group, base->object, scene, base); | ||||
| updated = true; | updated = true; | ||||
| } | } | ||||
| Context not available. | |||||
| * we could sckip all the dependency check and just consider | * we could sckip all the dependency check and just consider | ||||
| * operator is finished. | * operator is finished. | ||||
| */ | */ | ||||
| if (group_link_early_exit_check(group, ob)) { | if (BKE_group_object_exists(group, ob)) { | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| Context not available. | |||||
| * contains our current object. | * contains our current object. | ||||
| */ | */ | ||||
| BKE_main_id_tag_listbase(&bmain->group, true); | BKE_main_id_tag_listbase(&bmain->group, true); | ||||
| if (check_object_instances_group_recursive(ob, group)) { | if (BKE_group_dependency_cycles_check(ob, group)) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected"); | BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| Context not available. | |||||