Merge branch 'master' into blender2.8
[blender.git] / source / blender / blenkernel / intern / collision.c
index 65c84187307283f59b085518c2bc2cb4107bba9d..d3aa52509557f33482a950467052076353ee5b9c 100644 (file)
@@ -33,8 +33,8 @@
 #include "MEM_guardedalloc.h"
 
 #include "DNA_cloth_types.h"
+#include "DNA_collection_types.h"
 #include "DNA_effect_types.h"
-#include "DNA_group_types.h"
 #include "DNA_object_types.h"
 #include "DNA_object_force_types.h"
 #include "DNA_scene_types.h"
@@ -46,7 +46,9 @@
 #include "BLI_edgehash.h"
 
 #include "BKE_cloth.h"
+#include "BKE_collection.h"
 #include "BKE_effect.h"
+#include "BKE_layer.h"
 #include "BKE_modifier.h"
 #include "BKE_scene.h"
 
 #include "BLI_kdopbvh.h"
 #include "BKE_collision.h"
 
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
+
 #ifdef WITH_ELTOPO
 #include "eltopo-capi.h"
 #endif
@@ -477,139 +483,143 @@ static CollPair* cloth_collision(ModifierData *md1, ModifierData *md2,
        return collpair;
 }
 
-static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned int *maxobj, Object *ob, Object *self, int level, unsigned int modifier_type)
+static void add_collision_object(ListBase *relations, Object *ob, int level, unsigned int modifier_type)
 {
        CollisionModifierData *cmd= NULL;
 
-       if (ob == self)
-               return;
-
        /* only get objects with collision modifier */
        if (((modifier_type == eModifierType_Collision) && ob->pd && ob->pd->deflect) || (modifier_type != eModifierType_Collision))
                cmd= (CollisionModifierData *)modifiers_findByType(ob, modifier_type);
 
        if (cmd) {
-               /* extend array */
-               if (*numobj >= *maxobj) {
-                       *maxobj *= 2;
-                       *objs= MEM_reallocN(*objs, sizeof(Object *)*(*maxobj));
-               }
-
-               (*objs)[*numobj] = ob;
-               (*numobj)++;
+               CollisionRelation *relation = MEM_callocN(sizeof(CollisionRelation), "CollisionRelation");
+               relation->ob = ob;
+               BLI_addtail(relations, relation);
        }
 
        /* objects in dupli groups, one level only for now */
+       /* TODO: this doesn't really work, we are not taking into account the
+        * dupli transforms and can get objects in the list multiple times. */
        if (ob->dup_group && level == 0) {
-               GroupObject *go;
-               Group *group= ob->dup_group;
+               Collection *collection= ob->dup_group;
 
                /* add objects */
-               for (go= group->gobject.first; go; go= go->next)
-                       add_collision_object(objs, numobj, maxobj, go->ob, self, level+1, modifier_type);
+               FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object)
+               {
+                       add_collision_object(relations, object, level+1, modifier_type);
+               }
+               FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
        }
 }
 
-// return all collision objects in scene
-// collision object will exclude self
-Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli)
+/* Create list of collision relations in the collection or entire scene.
+ * This is used by the depsgraph to build relations, as well as faster
+ * lookup of colliders during evaluation. */
+ListBase *BKE_collision_relations_create(Depsgraph *depsgraph, Collection *collection, unsigned int modifier_type)
 {
-       Base *base;
-       Object **objs;
-       GroupObject *go;
-       unsigned int numobj= 0, maxobj= 100;
-       int level = dupli ? 0 : 1;
-
-       objs= MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray");
-
-       /* gather all collision objects */
-       if (group) {
-               /* use specified group */
-               for (go= group->gobject.first; go; go= go->next)
-                       add_collision_object(&objs, &numobj, &maxobj, go->ob, self, level, modifier_type);
-       }
-       else {
-               Scene *sce_iter;
-               /* add objects in same layer in scene */
-               for (SETLOOPER(scene, sce_iter, base)) {
-                       if ( base->lay & layer )
-                               add_collision_object(&objs, &numobj, &maxobj, base->object, self, level, modifier_type);
+       ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+       Base *base = BKE_collection_or_layer_objects(view_layer, collection);
+       const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+       const int base_flag = (for_render) ? BASE_ENABLED_RENDER : BASE_ENABLED_VIEWPORT;
 
+       ListBase *relations = MEM_callocN(sizeof(ListBase), "CollisionRelation list");
+
+       for (; base; base = base->next) {
+               if (base->flag & base_flag) {
+                       add_collision_object(relations, base->object, 0, modifier_type);
                }
        }
 
-       *numcollobj= numobj;
-
-       return objs;
+       return relations;
 }
 
-Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type)
+void BKE_collision_relations_free(ListBase *relations)
 {
-       /* Need to check for active layers, too.
-          Otherwise this check fails if the objects are not on the same layer - DG */
-       return get_collisionobjects_ext(scene, self, group, self->lay | scene->lay, numcollobj, modifier_type, true);
+       if (relations) {
+               BLI_freelistN(relations);
+               MEM_freeN(relations);
+       }
 }
 
-static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self, int level)
+/* Create effective list of colliders from relations built beforehand.
+ * Self will be excluded. */
+Object **BKE_collision_objects_create(Depsgraph *depsgraph, Object *self, Collection *collection, unsigned int *numcollobj, unsigned int modifier_type)
 {
-       CollisionModifierData *cmd= NULL;
-       ColliderCache *col;
+       ListBase *relations = DEG_get_collision_relations(depsgraph, collection, modifier_type);
 
-       if (ob == self)
-               return;
+       if (!relations) {
+               *numcollobj = 0;
+               return NULL;
+       }
 
-       if (ob->pd && ob->pd->deflect)
-               cmd =(CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
+       int maxnum = BLI_listbase_count(relations);
+       int num = 0;
+       Object **objects = MEM_callocN(sizeof(Object*) * maxnum, __func__);
 
-       if (cmd && cmd->bvhtree) {
-               if (*objs == NULL)
-                       *objs = MEM_callocN(sizeof(ListBase), "ColliderCache array");
+       for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
+               /* Get evaluated object. */
+               Object *ob = (Object*)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
 
-               col = MEM_callocN(sizeof(ColliderCache), "ColliderCache");
-               col->ob = ob;
-               col->collmd = cmd;
-               /* make sure collider is properly set up */
-               collision_move_object(cmd, 1.0, 0.0);
-               BLI_addtail(*objs, col);
+               if (ob != self) {
+                       objects[num] = ob;
+                       num++;
+               }
        }
 
-       /* objects in dupli groups, one level only for now */
-       if (ob->dup_group && level == 0) {
-               GroupObject *go;
-               Group *group= ob->dup_group;
+       if (num == 0) {
+               MEM_freeN(objects);
+               objects = NULL;
+       }
 
-               /* add objects */
-               for (go= group->gobject.first; go; go= go->next)
-                       add_collider_cache_object(objs, go->ob, self, level+1);
+       *numcollobj = num;
+       return objects;
+}
+
+void BKE_collision_objects_free(Object **objects)
+{
+       if (objects) {
+               MEM_freeN(objects);
        }
 }
 
-ListBase *get_collider_cache(Scene *scene, Object *self, Group *group)
+/* Create effective list of colliders from relations built beforehand.
+ * Self will be excluded. */
+ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collection *collection)
 {
-       GroupObject *go;
-       ListBase *objs= NULL;
+       ListBase *relations = DEG_get_collision_relations(depsgraph, collection, eModifierType_Collision);
+       ListBase *cache = NULL;
 
-       /* add object in same layer in scene */
-       if (group) {
-               for (go= group->gobject.first; go; go= go->next)
-                       add_collider_cache_object(&objs, go->ob, self, 0);
+       if (!relations) {
+               return NULL;
        }
-       else {
-               Scene *sce_iter;
-               Base *base;
 
-               /* add objects in same layer in scene */
-               for (SETLOOPER(scene, sce_iter, base)) {
-                       if (!self || (base->lay & self->lay))
-                               add_collider_cache_object(&objs, base->object, self, 0);
+       for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
+               /* Get evaluated object. */
+               Object *ob = (Object*)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
+
+               if (ob == self) {
+                       continue;
+               }
+
+               CollisionModifierData *cmd = (CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
+               if (cmd && cmd->bvhtree) {
+                       if (cache == NULL) {
+                               cache = MEM_callocN(sizeof(ListBase), "ColliderCache array");
+                       }
 
+                       ColliderCache *col = MEM_callocN(sizeof(ColliderCache), "ColliderCache");
+                       col->ob = ob;
+                       col->collmd = cmd;
+                       /* make sure collider is properly set up */
+                       collision_move_object(cmd, 1.0, 0.0);
+                       BLI_addtail(cache, col);
                }
        }
 
-       return objs;
+       return cache;
 }
 
-void free_collider_cache(ListBase **colliders)
+void BKE_collider_cache_free(ListBase **colliders)
 {
        if (*colliders) {
                BLI_freelistN(*colliders);
@@ -676,7 +686,7 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision
 }
 
 // cloth - object collisions
-int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, float dt )
+int cloth_bvh_objcollision(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt )
 {
        Cloth *cloth= clmd->clothObject;
        BVHTree *cloth_bvh= cloth->bvhtree;
@@ -702,7 +712,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
        bvhtree_update_from_cloth ( clmd, 1 ); // 0 means STATIC, 1 means MOVING (see later in this function)
        bvhselftree_update_from_cloth ( clmd, 0 ); // 0 means STATIC, 1 means MOVING (see later in this function)
 
-       collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+       collobjs = BKE_collision_objects_create(depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
 
        if (!collobjs)
                return 0;
@@ -884,8 +894,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
        }
        while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) );
 
-       if (collobjs)
-               MEM_freeN(collobjs);
+       BKE_collision_objects_free(collobjs);
 
        return 1|MIN2 ( ret, 1 );
 }
@@ -1197,7 +1206,7 @@ static int cloth_points_objcollisions_resolve(
 }
 
 // cloth - object collisions
-int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, float dt)
+int cloth_points_objcollision(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt)
 {
        Cloth *cloth= clmd->clothObject;
        BVHTree *cloth_bvh;
@@ -1230,7 +1239,7 @@ int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, f
        /* balance tree */
        BLI_bvhtree_balance(cloth_bvh);
 
-       collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+       collobjs = BKE_collision_objects_create(depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
        if (!collobjs)
                return 0;
 
@@ -1311,15 +1320,14 @@ int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, f
        }
        while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) );
 
-       if (collobjs)
-               MEM_freeN(collobjs);
+       BKE_collision_objects_free(collobjs);
 
        BLI_bvhtree_free(cloth_bvh);
 
        return 1|MIN2 ( ret, 1 );
 }
 
-void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step, float dt,
+void cloth_find_point_contacts(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt,
                                ColliderContacts **r_collider_contacts, int *r_totcolliders)
 {
        Cloth *cloth= clmd->clothObject;
@@ -1353,7 +1361,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
        /* balance tree */
        BLI_bvhtree_balance(cloth_bvh);
 
-       collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+       collobjs = BKE_collision_objects_create(depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
        if (!collobjs) {
                *r_collider_contacts = NULL;
                *r_totcolliders = 0;
@@ -1412,8 +1420,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
                        MEM_freeN(overlap);
        }
 
-       if (collobjs)
-               MEM_freeN(collobjs);
+       BKE_collision_objects_free(collobjs);
 
        BLI_bvhtree_free(cloth_bvh);