EPhysics: properly handle world delete
authorBruno Dilly <bdilly@profusion.mobi>
Fri, 10 Aug 2012 21:03:29 +0000 (21:03 +0000)
committerBruno Dilly <bdilly@profusion.mobi>
Fri, 10 Aug 2012 21:03:29 +0000 (21:03 +0000)
SVN revision: 75140

legacy/ephysics/src/lib/ephysics_world.cpp

index 6b5e21b..5a439fe 100644 (file)
@@ -36,20 +36,23 @@ struct _EPhysics_World {
      double last_update;
      double rate;
      double fixed_time_step;
+     double max_sleeping_time;
      Eina_Bool running:1;
      Eina_Bool active:1;
+     Eina_Bool deleted:1;
      Eina_Bool outside_autodel:1;
      Eina_Bool outside_top:1;
      Eina_Bool outside_bottom:1;
      Eina_Bool outside_left:1;
      Eina_Bool outside_right:1;
-     double max_sleeping_time;
 };
 
 static int _ephysics_world_init_count = 0;
 static int _worlds_running = 0;
 static Eina_Inlist *_worlds = NULL;
+static Eina_List *_worlds_to_delete = NULL;
 static Ecore_Animator *_anim_simulate = NULL;
+static int _worlds_walking = 0;
 
 struct _ephysics_world_ovelap_filter_cb : public btOverlapFilterCallback
 {
@@ -124,13 +127,51 @@ _ephysics_world_tick_cb(btDynamicsWorld *dynamics_world, btScalar timeStep)
         cb->func(cb->data, world, NULL);
 }
 
+static void
+_ephysics_world_free(EPhysics_World *world)
+{
+   EPhysics_World_Callback *cb;
+   EPhysics_Body *body;
+
+   _worlds = eina_inlist_remove(_worlds, EINA_INLIST_GET(world));
+
+   while (world->callbacks)
+     {
+        cb = EINA_INLIST_CONTAINER_GET(world->callbacks,
+                                       EPhysics_World_Callback);
+        world->callbacks = eina_inlist_remove(world->callbacks,
+                                              world->callbacks);
+        free(cb);
+     }
+
+   while (world->bodies)
+     {
+        body = EINA_INLIST_CONTAINER_GET(world->bodies, EPhysics_Body);
+        world->bodies = eina_inlist_remove(world->bodies, world->bodies);
+        ephysics_orphan_body_del(body);
+     }
+
+   ephysics_camera_del(world->camera);
+   delete world->dynamics_world;
+   delete world->solver;
+   delete world->dispatcher;
+   delete world->collision;
+   delete world->broadphase;
+
+   free(world);
+   INF("World %p deleted.", world);
+}
+
 static Eina_Bool
 _simulate_worlds(void *data)
 {
    Eina_Inlist *lworlds = (Eina_Inlist *) data;
    EPhysics_World *world;
    double time_now;
+   void *wrld;
 
+   ephysics_init();
+   _worlds_walking++;
    EINA_INLIST_FOREACH(lworlds, world)
      {
         double time_now, delta;
@@ -146,6 +187,18 @@ _simulate_worlds(void *data)
         world->dynamics_world->stepSimulation(delta, world->max_sub_steps,
                                               world->fixed_time_step);
      }
+   _worlds_walking--;
+
+   if (_worlds_walking > 0)
+     {
+        ephysics_shutdown();
+        return EINA_TRUE;
+     }
+
+   EINA_LIST_FREE(_worlds_to_delete, wrld)
+      _ephysics_world_free((EPhysics_World *)wrld);
+
+   ephysics_shutdown();
 
    return EINA_TRUE;
 }
@@ -247,7 +300,6 @@ ephysics_world_shutdown(void)
      {
         EPhysics_World *world = EINA_INLIST_CONTAINER_GET(
            _worlds, EPhysics_World);
-        _worlds = eina_inlist_remove(_worlds, _worlds);
         ephysics_world_del(world);
      }
 
@@ -422,7 +474,6 @@ EAPI void
 ephysics_world_del(EPhysics_World *world)
 {
    EPhysics_World_Callback *cb;
-   EPhysics_Body *body;
 
    if (!world)
      {
@@ -430,6 +481,9 @@ ephysics_world_del(EPhysics_World *world)
         return;
      }
 
+   if (world->deleted) return;
+
+   world->deleted = EINA_TRUE;
    EINA_INLIST_FOREACH(world->callbacks, cb)
      {
         if (cb->type == EPHYSICS_CALLBACK_WORLD_DEL)
@@ -437,33 +491,15 @@ ephysics_world_del(EPhysics_World *world)
      }
 
    ephysics_world_running_set(world, EINA_FALSE);
-   _worlds = eina_inlist_remove(_worlds, EINA_INLIST_GET(world));
-
-   while (world->callbacks)
-     {
-        cb = EINA_INLIST_CONTAINER_GET(world->callbacks,
-                                       EPhysics_World_Callback);
-        world->callbacks = eina_inlist_remove(world->callbacks,
-                                              world->callbacks);
-        free(cb);
-     }
 
-   while (world->bodies)
+   if (_worlds_walking > 0)
      {
-        body = EINA_INLIST_CONTAINER_GET(world->bodies, EPhysics_Body);
-        world->bodies = eina_inlist_remove(world->bodies, world->bodies);
-        ephysics_orphan_body_del(body);
+        _worlds_to_delete = eina_list_append(_worlds_to_delete, world);
+        INF("World %p marked to delete.", world);
+        return;
      }
 
-   ephysics_camera_del(world->camera);
-   delete world->dynamics_world;
-   delete world->solver;
-   delete world->dispatcher;
-   delete world->collision;
-   delete world->broadphase;
-
-   free(world);
-   INF("World %p deleted.", world);
+   _ephysics_world_free(world);
 }
 
 EAPI void