Merged changes in the trunk up to revision 47977.
[blender.git] / source / blender / blenkernel / intern / object.c
index b656cb6d8dea252633635ed9f977a500e7caeebc..1d045d4142d73be237aee506318b5aaca6aafe3a 100644 (file)
@@ -63,6 +63,7 @@
 #include "BLI_math.h"
 #include "BLI_pbvh.h"
 #include "BLI_utildefines.h"
+#include "BLI_linklist.h"
 
 #include "BKE_main.h"
 #include "BKE_global.h"
@@ -3086,3 +3087,135 @@ MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, int use_default)
 
        return clip;
 }
+
+
+/*
+ * Find an associated Armature object
+ */
+static Object *obrel_armature_find(Object *ob)
+{
+       Object *ob_arm = NULL;
+
+       if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) {
+               ob_arm = ob->parent;
+       }
+       else {
+               ModifierData *mod;
+               for (mod = (ModifierData *)ob->modifiers.first; mod; mod = mod->next) {
+                       if (mod->type == eModifierType_Armature) {
+                               ob_arm = ((ArmatureModifierData *)mod)->object;
+                       }
+               }
+       }
+
+       return ob_arm;
+}
+
+static int obrel_is_recursive_child(Object *ob, Object *child) {
+       Object *par;
+       for (par = child->parent; par; par = par->parent) {
+               if (par == ob) {
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+
+static int obrel_list_test(Object *ob)
+{
+       return ob && !(ob->id.flag & LIB_DOIT);
+}
+
+static void obrel_list_add(LinkNode **links, Object *ob)
+{
+       BLI_linklist_prepend(links, ob);
+       ob->id.flag |= LIB_DOIT;
+}
+
+/*
+ * Iterates over all objects of the given scene.
+ * Depending on the eObjectSet flag:
+ * collect either OB_SET_ALL, OB_SET_VISIBLE or OB_SET_SELECTED objects.
+ * If OB_SET_VISIBLE or OB_SET_SELECTED are collected, 
+ * then also add related objects according to the given includeFilters.
+ */
+struct LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter)
+{
+       LinkNode *links = NULL;
+
+       Base *base;
+
+       /* Remove markers from all objects */
+       for (base = scene->base.first; base; base = base->next) {
+               base->object->id.flag &= ~LIB_DOIT;
+       }
+
+       /* iterate over all selected and visible objects */
+       for (base = scene->base.first; base; base = base->next) {
+               if (objectSet == OB_SET_ALL) {
+                       // as we get all anyways just add it
+                       Object *ob = base->object;
+                       obrel_list_add(&links, ob);
+               }
+               else {
+                       if ((objectSet == OB_SET_SELECTED && TESTBASELIB_BGMODE(((View3D *)NULL), scene, base)) ||
+                           (objectSet == OB_SET_VISIBLE  && BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, base)))
+                       {
+                               Object *ob = base->object;
+
+                               if (obrel_list_test(ob))
+                                       obrel_list_add(&links, ob);
+
+                               /* parent relationship */
+                               if (includeFilter & (OB_REL_PARENT | OB_REL_PARENT_RECURSIVE)) {
+                                       Object *parent = ob->parent;
+                                       if (obrel_list_test(parent)) {
+
+                                               obrel_list_add(&links, parent);
+
+                                               /* recursive parent relationship */
+                                               if (includeFilter & OB_REL_PARENT_RECURSIVE) {
+                                                       parent = parent->parent;
+                                                       while (obrel_list_test(parent)) {
+
+                                                               obrel_list_add(&links, parent);
+                                                               parent = parent->parent;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               /* child relationship */
+                               if (includeFilter & (OB_REL_CHILDREN | OB_REL_CHILDREN_RECURSIVE)) {
+                                       Base *local_base;
+                                       for (local_base = scene->base.first; local_base; local_base = local_base->next) {
+                                               if (BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, local_base)) {
+
+                                                       Object *child = local_base->object;
+                                                       if (obrel_list_test(child)) {
+                                                               if ((includeFilter & OB_REL_CHILDREN_RECURSIVE && obrel_is_recursive_child(ob, child)) ||
+                                                                   (includeFilter & OB_REL_CHILDREN && child->parent && child->parent == ob))
+                                                               {
+                                                                       obrel_list_add(&links, child);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+
+
+                               /* include related armatures */
+                               if (includeFilter & OB_REL_MOD_ARMATURE) {
+                                       Object *arm = obrel_armature_find(ob);
+                                       if (obrel_list_test(arm)) {
+                                               obrel_list_add(&links, arm);
+                                       }
+                               }
+
+                       }
+               }
+       }
+
+       return links;
+}