2012-06-26 15:36:12 -07:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "ephysics_private.h"
|
|
|
|
#include <Ecore.h>
|
|
|
|
#include <Evas.h>
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2012-08-22 13:04:39 -07:00
|
|
|
#define DEFAULT_GRAVITY btVector3(0, -9.8, 0)
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
typedef struct _Simulation_Msg Simulation_Msg;
|
|
|
|
|
|
|
|
struct _Simulation_Msg {
|
|
|
|
EPhysics_Body *body_0;
|
|
|
|
EPhysics_Body *body_1;
|
|
|
|
btVector3 pos_a;
|
|
|
|
btVector3 pos_b;
|
|
|
|
Eina_Bool tick:1;
|
|
|
|
};
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
typedef struct _EPhysics_World_Callback EPhysics_World_Callback;
|
|
|
|
|
|
|
|
struct _EPhysics_World_Callback {
|
|
|
|
EINA_INLIST;
|
|
|
|
void (*func) (void *data, EPhysics_World *world, void *event_info);
|
|
|
|
void *data;
|
2012-07-02 19:09:34 -07:00
|
|
|
EPhysics_Callback_World_Type type;
|
2012-08-10 14:04:22 -07:00
|
|
|
Eina_Bool deleted:1;
|
2012-06-26 15:36:12 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _EPhysics_World {
|
2012-08-10 14:03:01 -07:00
|
|
|
EINA_INLIST;
|
2012-10-15 14:54:29 -07:00
|
|
|
|
|
|
|
struct {
|
|
|
|
Evas_Coord x;
|
|
|
|
Evas_Coord y;
|
|
|
|
Evas_Coord z;
|
|
|
|
Evas_Coord w;
|
|
|
|
Evas_Coord h;
|
|
|
|
Evas_Coord d;
|
|
|
|
} geometry;
|
|
|
|
|
2012-10-10 13:32:29 -07:00
|
|
|
btBroadphaseInterface *broadphase;
|
|
|
|
btDefaultCollisionConfiguration *collision;
|
|
|
|
btCollisionDispatcher *dispatcher;
|
|
|
|
btSequentialImpulseConstraintSolver *solver;
|
|
|
|
btSoftRigidDynamicsWorld *dynamics_world;
|
|
|
|
btSoftBodyWorldInfo *world_info;
|
|
|
|
btSoftBodySolver *soft_solver;
|
2012-10-04 15:38:00 -07:00
|
|
|
btOverlapFilterCallback *filter_cb;
|
2012-06-26 15:36:12 -07:00
|
|
|
|
2012-10-15 14:54:29 -07:00
|
|
|
EPhysics_Body *boundaries[6];
|
2012-06-26 15:36:12 -07:00
|
|
|
EPhysics_Camera *camera;
|
|
|
|
Eina_Inlist *callbacks;
|
2012-08-10 14:03:06 -07:00
|
|
|
Eina_Inlist *bodies;
|
2012-08-10 14:03:39 -07:00
|
|
|
Eina_List *to_delete;
|
2012-08-10 14:04:22 -07:00
|
|
|
Eina_List *cb_to_delete;
|
2012-08-16 14:34:44 -07:00
|
|
|
Eina_List *constraints;
|
2012-10-04 15:38:06 -07:00
|
|
|
Ecore_Thread *simulation_th;
|
|
|
|
Ecore_Thread *cur_th;
|
2012-07-31 12:55:52 -07:00
|
|
|
int max_sub_steps;
|
2012-08-10 14:04:22 -07:00
|
|
|
int cb_walking;
|
2012-08-22 13:04:39 -07:00
|
|
|
int soft_body_ref;
|
2012-10-04 15:38:06 -07:00
|
|
|
int pending_ticks;
|
2012-06-26 15:36:12 -07:00
|
|
|
double last_update;
|
|
|
|
double rate;
|
2012-07-31 12:55:52 -07:00
|
|
|
double fixed_time_step;
|
2012-08-10 14:03:29 -07:00
|
|
|
double max_sleeping_time;
|
2012-10-04 15:38:06 -07:00
|
|
|
Eina_Lock mutex;
|
|
|
|
Eina_Condition condition;
|
2012-10-18 16:27:26 -07:00
|
|
|
|
2012-10-30 11:31:32 -07:00
|
|
|
struct {
|
|
|
|
Evas_Coord lx;
|
|
|
|
Evas_Coord ly;
|
|
|
|
Evas_Coord lz;
|
|
|
|
int lr;
|
|
|
|
int lg;
|
|
|
|
int lb;
|
|
|
|
int ar;
|
|
|
|
int ag;
|
|
|
|
int ab;
|
|
|
|
Eina_Bool all_bodies:1;
|
|
|
|
} light;
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
Eina_Bool running:1;
|
2012-10-04 15:40:52 -07:00
|
|
|
Eina_Bool ticked:1;
|
2012-06-26 15:36:12 -07:00
|
|
|
Eina_Bool active:1;
|
2012-08-10 14:03:29 -07:00
|
|
|
Eina_Bool deleted:1;
|
2012-07-03 16:20:49 -07:00
|
|
|
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;
|
2012-10-15 14:54:35 -07:00
|
|
|
Eina_Bool outside_front:1;
|
|
|
|
Eina_Bool outside_back:1;
|
2012-10-04 15:38:06 -07:00
|
|
|
Eina_Bool pending_simulation:1;
|
2012-10-25 14:55:23 -07:00
|
|
|
Eina_Bool stacking:1;
|
2012-12-03 13:29:03 -08:00
|
|
|
Eina_Bool force_update:1;
|
2012-06-26 15:36:12 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static int _ephysics_world_init_count = 0;
|
|
|
|
static int _worlds_running = 0;
|
2012-08-10 14:03:01 -07:00
|
|
|
static Eina_Inlist *_worlds = NULL;
|
2012-08-10 14:03:29 -07:00
|
|
|
static Eina_List *_worlds_to_delete = NULL;
|
2012-06-26 15:36:12 -07:00
|
|
|
static Ecore_Animator *_anim_simulate = NULL;
|
2012-08-10 14:03:29 -07:00
|
|
|
static int _worlds_walking = 0;
|
2012-06-26 15:36:12 -07:00
|
|
|
|
2012-12-03 13:29:03 -08:00
|
|
|
void
|
|
|
|
ephysics_world_force_update_set(EPhysics_World *world, Eina_Bool force_update)
|
|
|
|
{
|
|
|
|
world->force_update = force_update;
|
|
|
|
}
|
|
|
|
|
2012-08-22 13:04:39 -07:00
|
|
|
btSoftBodyWorldInfo *
|
|
|
|
ephysics_world_info_get(const EPhysics_World *world)
|
|
|
|
{
|
|
|
|
return world->world_info;
|
|
|
|
}
|
|
|
|
|
2012-07-27 07:49:53 -07:00
|
|
|
struct _ephysics_world_ovelap_filter_cb : public btOverlapFilterCallback
|
|
|
|
{
|
2012-08-10 14:03:39 -07:00
|
|
|
virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0,
|
|
|
|
btBroadphaseProxy* proxy1) const
|
2012-07-27 07:49:53 -07:00
|
|
|
{
|
|
|
|
btCollisionObject *coll0 = (btCollisionObject *)proxy0->m_clientObject;
|
|
|
|
btCollisionObject *coll1 = (btCollisionObject *)proxy1->m_clientObject;
|
|
|
|
|
|
|
|
EPhysics_Body *body0 = (EPhysics_Body *)coll0->getUserPointer();
|
|
|
|
EPhysics_Body *body1 = (EPhysics_Body *)coll1->getUserPointer();
|
|
|
|
|
|
|
|
if ((!body0 || !body1) || (ephysics_body_filter_collision(body0, body1)))
|
|
|
|
return EINA_TRUE;
|
|
|
|
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-08-16 14:35:14 -07:00
|
|
|
static inline void
|
2012-10-10 12:17:44 -07:00
|
|
|
_ephysics_world_gravity_set(EPhysics_World *world, double gx, double gy, double gz, double rate)
|
2012-08-16 14:35:14 -07:00
|
|
|
{
|
2012-08-22 13:04:39 -07:00
|
|
|
btVector3 gravity;
|
|
|
|
|
2012-10-10 12:17:44 -07:00
|
|
|
gravity = btVector3(gx / rate, -gy / rate, gz / rate);
|
2012-08-22 13:04:39 -07:00
|
|
|
world->dynamics_world->setGravity(gravity);
|
|
|
|
world->world_info->m_gravity = gravity;
|
2012-08-16 14:35:14 -07:00
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
static void
|
|
|
|
_ephysics_world_th_cancel(EPhysics_World *world)
|
|
|
|
{
|
|
|
|
_worlds = eina_inlist_remove(_worlds, EINA_INLIST_GET(world));
|
|
|
|
if (!ecore_thread_cancel(world->simulation_th))
|
|
|
|
eina_condition_signal(&world->condition);
|
|
|
|
}
|
|
|
|
|
2012-08-10 14:04:22 -07:00
|
|
|
static void
|
|
|
|
_ephysics_world_event_callback_call(EPhysics_World *world, EPhysics_Callback_World_Type type, void *event_info)
|
|
|
|
{
|
|
|
|
EPhysics_World_Callback *cb;
|
|
|
|
void *clb;
|
|
|
|
|
|
|
|
world->cb_walking++;
|
|
|
|
EINA_INLIST_FOREACH(world->callbacks, cb)
|
|
|
|
{
|
|
|
|
if ((cb->type == type) && (!cb->deleted))
|
|
|
|
cb->func(cb->data, world, event_info);
|
|
|
|
}
|
|
|
|
world->cb_walking--;
|
|
|
|
|
|
|
|
if (world->cb_walking > 0) return;
|
|
|
|
|
|
|
|
EINA_LIST_FREE(world->cb_to_delete, clb)
|
|
|
|
{
|
|
|
|
cb = (EPhysics_World_Callback *)clb;
|
|
|
|
world->callbacks = eina_inlist_remove(world->callbacks,
|
|
|
|
EINA_INLIST_GET(cb));
|
|
|
|
free(cb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_ephysics_world_event_callback_del(EPhysics_World *world, EPhysics_World_Callback *cb)
|
|
|
|
{
|
|
|
|
if (cb->deleted) return;
|
|
|
|
|
|
|
|
cb->deleted = EINA_TRUE;
|
|
|
|
|
|
|
|
if (world->cb_walking)
|
|
|
|
{
|
|
|
|
world->cb_to_delete = eina_list_append(world->cb_to_delete, cb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->callbacks = eina_inlist_remove(world->callbacks,
|
|
|
|
EINA_INLIST_GET(cb));
|
|
|
|
free(cb);
|
|
|
|
}
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
static void
|
2012-10-04 15:38:06 -07:00
|
|
|
_ephysics_world_tick(btDynamicsWorld *dynamics_world)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
2012-07-27 07:50:36 -07:00
|
|
|
Eina_Bool world_active, camera_moved, tx, ty;
|
|
|
|
btCollisionObjectArray objects;
|
2012-10-04 15:40:16 -07:00
|
|
|
btCollisionObject *collision;
|
2012-07-27 07:50:36 -07:00
|
|
|
EPhysics_World *world;
|
|
|
|
EPhysics_Body *body;
|
2012-10-04 15:40:16 -07:00
|
|
|
btRigidBody *rigid_body;
|
2012-06-26 15:36:12 -07:00
|
|
|
|
|
|
|
world = (EPhysics_World *) dynamics_world->getWorldUserInfo();
|
|
|
|
|
2012-07-27 07:50:36 -07:00
|
|
|
world_active = EINA_FALSE;
|
|
|
|
|
|
|
|
ephysics_camera_tracked_body_get(world->camera, &body, &tx, &ty);
|
|
|
|
if ((body) && (tx || ty))
|
|
|
|
{
|
|
|
|
rigid_body = ephysics_body_rigid_body_get(body);
|
2012-08-13 15:24:28 -07:00
|
|
|
if ((rigid_body) && (rigid_body->isActive()))
|
|
|
|
ephysics_camera_target_moved(world->camera, body);
|
2012-07-27 07:50:36 -07:00
|
|
|
}
|
|
|
|
|
2012-08-13 15:24:28 -07:00
|
|
|
camera_moved = ephysics_camera_moved_get(world->camera);
|
|
|
|
|
2012-07-27 07:50:36 -07:00
|
|
|
objects = dynamics_world->getCollisionObjectArray();
|
2012-06-26 15:36:12 -07:00
|
|
|
for (int i = 0; i < objects.size(); i++)
|
|
|
|
{
|
2012-10-04 15:40:16 -07:00
|
|
|
collision = objects[i];
|
|
|
|
|
|
|
|
if (!collision)
|
2012-06-26 15:36:12 -07:00
|
|
|
continue;
|
|
|
|
|
2012-10-04 15:40:16 -07:00
|
|
|
body = (EPhysics_Body *) collision->getUserPointer();
|
|
|
|
if (collision->isActive())
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
|
|
|
ephysics_body_active_set(body, EINA_TRUE);
|
|
|
|
ephysics_body_evas_object_update_select(body);
|
|
|
|
world_active = EINA_TRUE;
|
|
|
|
}
|
|
|
|
else
|
2012-07-27 07:50:36 -07:00
|
|
|
{
|
|
|
|
ephysics_body_active_set(body, EINA_FALSE);
|
2012-12-03 13:29:03 -08:00
|
|
|
if (camera_moved || world->force_update)
|
2012-07-27 07:50:36 -07:00
|
|
|
ephysics_body_evas_object_update_select(body);
|
|
|
|
}
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
2012-10-25 14:55:23 -07:00
|
|
|
if (world->stacking)
|
|
|
|
ephysics_body_evas_objects_restack(world);
|
2012-10-16 16:12:59 -07:00
|
|
|
|
2012-12-03 13:29:03 -08:00
|
|
|
world->force_update = EINA_FALSE;
|
2012-08-13 15:24:28 -07:00
|
|
|
if (camera_moved)
|
|
|
|
{
|
2012-09-04 15:42:10 -07:00
|
|
|
ephysics_camera_moved_set(world->camera, EINA_FALSE);
|
2012-08-13 15:24:28 -07:00
|
|
|
_ephysics_world_event_callback_call(
|
|
|
|
world, EPHYSICS_CALLBACK_WORLD_CAMERA_MOVED, world->camera);
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
if (world->active == world_active) goto body_del;
|
2012-06-26 15:36:12 -07:00
|
|
|
world->active = world_active;
|
2012-10-04 15:38:06 -07:00
|
|
|
if (world_active) goto body_del;
|
2012-06-26 15:36:12 -07:00
|
|
|
|
2012-08-10 14:04:22 -07:00
|
|
|
_ephysics_world_event_callback_call(world, EPHYSICS_CALLBACK_WORLD_STOPPED,
|
|
|
|
NULL);
|
2012-10-04 15:38:06 -07:00
|
|
|
|
|
|
|
body_del:
|
2012-12-05 11:27:53 -08:00
|
|
|
if (world_active)
|
|
|
|
_ephysics_world_event_callback_call(world, EPHYSICS_CALLBACK_WORLD_UPDATE,
|
|
|
|
NULL);
|
2012-10-04 15:38:06 -07:00
|
|
|
world->pending_ticks--;
|
|
|
|
if (!world->pending_ticks)
|
|
|
|
{
|
|
|
|
void *bd;
|
|
|
|
EINA_LIST_FREE(world->to_delete, bd)
|
|
|
|
ephysics_world_body_del(world, (EPhysics_Body*)bd);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((world->pending_simulation) && (!world->pending_ticks))
|
|
|
|
{
|
|
|
|
world->pending_simulation = EINA_FALSE;
|
|
|
|
eina_condition_signal(&world->condition);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-10-04 15:40:52 -07:00
|
|
|
_ephysics_world_tick_dispatch(EPhysics_World *world)
|
2012-10-04 15:38:06 -07:00
|
|
|
{
|
|
|
|
Simulation_Msg *msg;
|
|
|
|
|
2012-10-04 15:40:52 -07:00
|
|
|
if (!world->ticked)
|
|
|
|
return;
|
|
|
|
|
|
|
|
world->ticked = EINA_FALSE;
|
|
|
|
world->pending_ticks++;
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
msg = (Simulation_Msg *) calloc(1, sizeof(Simulation_Msg));
|
|
|
|
msg->tick = EINA_TRUE;
|
2012-10-04 15:40:52 -07:00
|
|
|
ecore_thread_feedback(world->cur_th, msg);
|
|
|
|
}
|
2012-10-04 15:38:06 -07:00
|
|
|
|
2012-10-04 15:40:52 -07:00
|
|
|
static void
|
2013-01-03 14:10:40 -08:00
|
|
|
_ephysics_world_tick_cb(btDynamicsWorld *dynamics_world, btScalar timeStep EINA_UNUSED)
|
2012-10-04 15:40:52 -07:00
|
|
|
{
|
|
|
|
EPhysics_World *world;
|
2012-10-04 15:38:06 -07:00
|
|
|
world = (EPhysics_World *) dynamics_world->getWorldUserInfo();
|
2012-10-04 15:40:52 -07:00
|
|
|
world->ticked = EINA_TRUE;
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
2012-09-12 14:49:47 -07:00
|
|
|
static void
|
|
|
|
_ephysics_world_body_del(EPhysics_World *world, EPhysics_Body *body)
|
|
|
|
{
|
|
|
|
btSoftBody *soft_body;
|
|
|
|
|
2012-10-04 15:40:16 -07:00
|
|
|
if (ephysics_body_rigid_body_get(body))
|
|
|
|
world->dynamics_world->removeRigidBody(ephysics_body_rigid_body_get(body));
|
2012-09-12 14:49:47 -07:00
|
|
|
|
|
|
|
soft_body = ephysics_body_soft_body_get(body);
|
|
|
|
if (soft_body)
|
|
|
|
{
|
|
|
|
world->dynamics_world->removeSoftBody(soft_body);
|
|
|
|
--world->soft_body_ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->bodies = eina_inlist_remove(world->bodies, EINA_INLIST_GET(body));
|
|
|
|
ephysics_orphan_body_del(body);
|
|
|
|
}
|
|
|
|
|
2012-11-09 10:58:51 -08:00
|
|
|
static void
|
|
|
|
_ephysics_world_boundary_del(EPhysics_World *world, EPhysics_Body *body)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < EPHYSICS_WORLD_BOUNDARY_LAST; i++)
|
|
|
|
{
|
|
|
|
if (world->boundaries[i] == body)
|
|
|
|
{
|
|
|
|
world->boundaries[i] = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-12 14:49:47 -07:00
|
|
|
Eina_Bool
|
|
|
|
ephysics_world_body_del(EPhysics_World *world, EPhysics_Body *body)
|
|
|
|
{
|
|
|
|
EPhysics_Body *bd;
|
|
|
|
|
2012-11-09 10:58:51 -08:00
|
|
|
if (body->boundary)
|
|
|
|
_ephysics_world_boundary_del(world, body);
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
if (world->pending_ticks)
|
2012-09-12 14:49:47 -07:00
|
|
|
{
|
|
|
|
world->to_delete = eina_list_append(world->to_delete, body);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
_ephysics_world_body_del(world, body);
|
|
|
|
|
|
|
|
/* Activate all the bodies after a body is deleted.
|
|
|
|
Otherwise it can lead to scenarios when a body 1, below body 2 is deleted
|
|
|
|
and body 2 will stay freezed in the air. Gravity won't start to
|
|
|
|
act over it until it's activated again. */
|
|
|
|
EINA_INLIST_FOREACH(world->bodies, bd)
|
2012-10-04 15:40:16 -07:00
|
|
|
ephysics_body_activate(bd, EINA_TRUE);
|
2012-09-12 14:49:47 -07:00
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2012-08-10 14:03:29 -07:00
|
|
|
static void
|
|
|
|
_ephysics_world_free(EPhysics_World *world)
|
|
|
|
{
|
|
|
|
EPhysics_World_Callback *cb;
|
|
|
|
EPhysics_Body *body;
|
2012-08-16 14:34:44 -07:00
|
|
|
void *constraint;
|
2012-08-10 14:03:29 -07:00
|
|
|
|
|
|
|
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);
|
2012-09-12 14:49:47 -07:00
|
|
|
_ephysics_world_body_del(world, body);
|
2012-08-10 14:03:29 -07:00
|
|
|
}
|
|
|
|
|
2012-08-16 14:34:44 -07:00
|
|
|
EINA_LIST_FREE(world->constraints, constraint)
|
|
|
|
ephysics_constraint_del((EPhysics_Constraint *)constraint);
|
|
|
|
|
2012-08-10 14:03:29 -07:00
|
|
|
ephysics_camera_del(world->camera);
|
2012-09-12 14:49:47 -07:00
|
|
|
|
2012-10-04 15:38:00 -07:00
|
|
|
delete world->filter_cb;
|
2012-08-10 14:03:29 -07:00
|
|
|
delete world->dynamics_world;
|
|
|
|
delete world->solver;
|
2012-08-10 14:04:16 -07:00
|
|
|
delete world->broadphase;
|
2012-08-10 14:03:29 -07:00
|
|
|
delete world->dispatcher;
|
|
|
|
delete world->collision;
|
2012-08-22 13:04:39 -07:00
|
|
|
delete world->soft_solver;
|
|
|
|
delete world->world_info;
|
2012-08-10 14:03:29 -07:00
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_condition_free(&world->condition);
|
|
|
|
eina_lock_free(&world->mutex);
|
|
|
|
|
2012-08-10 14:03:29 -07:00
|
|
|
free(world);
|
|
|
|
INF("World %p deleted.", world);
|
2012-10-04 15:38:11 -07:00
|
|
|
ephysics_dom_count_dec();
|
2012-08-10 14:03:29 -07:00
|
|
|
}
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
static Eina_Bool
|
2013-01-03 14:10:40 -08:00
|
|
|
_simulate_worlds(void *data EINA_UNUSED)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
2012-08-10 14:03:01 -07:00
|
|
|
EPhysics_World *world;
|
2012-10-04 15:38:06 -07:00
|
|
|
void *wrld;
|
2012-06-26 15:36:12 -07:00
|
|
|
|
2012-08-10 14:03:29 -07:00
|
|
|
ephysics_init();
|
|
|
|
_worlds_walking++;
|
2012-08-21 10:47:29 -07:00
|
|
|
EINA_INLIST_FOREACH(_worlds, world)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
|
|
|
if (!world->running)
|
|
|
|
continue;
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
if (world->pending_ticks)
|
2012-09-12 14:49:29 -07:00
|
|
|
{
|
2012-10-04 15:38:06 -07:00
|
|
|
world->pending_simulation = EINA_TRUE;
|
|
|
|
continue;
|
2012-09-12 14:49:29 -07:00
|
|
|
}
|
2012-08-22 13:04:39 -07:00
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
world->pending_simulation = EINA_FALSE;
|
2012-08-10 14:03:39 -07:00
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_condition_signal(&world->condition);
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
2012-08-10 14:03:29 -07:00
|
|
|
_worlds_walking--;
|
|
|
|
|
|
|
|
if (_worlds_walking > 0)
|
|
|
|
{
|
|
|
|
ephysics_shutdown();
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
EINA_LIST_FREE(_worlds_to_delete, wrld)
|
2012-10-04 15:38:06 -07:00
|
|
|
_ephysics_world_th_cancel((EPhysics_World *)wrld);
|
2012-08-10 14:03:29 -07:00
|
|
|
|
|
|
|
ephysics_shutdown();
|
2012-06-26 15:36:12 -07:00
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_ephysics_world_contact_processed_cb(btManifoldPoint &cp, void *b0, void *b1)
|
|
|
|
{
|
|
|
|
btRigidBody *rigid_body_0, *rigid_body_1;
|
|
|
|
EPhysics_Body *body_0, *body_1;
|
2012-10-04 15:38:06 -07:00
|
|
|
EPhysics_World *world;
|
|
|
|
Simulation_Msg *msg;
|
2012-06-26 15:36:12 -07:00
|
|
|
|
|
|
|
rigid_body_0 = (btRigidBody *) b0;
|
|
|
|
rigid_body_1 = (btRigidBody *) b1;
|
|
|
|
|
|
|
|
body_0 = (EPhysics_Body *) rigid_body_0->getUserPointer();
|
|
|
|
body_1 = (EPhysics_Body *) rigid_body_1->getUserPointer();
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
world = ephysics_body_world_get(body_0);
|
|
|
|
|
|
|
|
msg = (Simulation_Msg *) calloc(1, sizeof(Simulation_Msg));
|
|
|
|
msg->body_0 = body_0;
|
|
|
|
msg->body_1 = body_1;
|
|
|
|
msg->pos_a = cp.getPositionWorldOnA();
|
|
|
|
msg->pos_b = cp.getPositionWorldOnB();
|
|
|
|
ecore_thread_feedback(world->cur_th, msg);
|
2012-07-27 07:49:20 -07:00
|
|
|
|
|
|
|
return EINA_TRUE;
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
2012-08-10 14:03:39 -07:00
|
|
|
ephysics_world_body_add(EPhysics_World *world, EPhysics_Body *body)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
2012-08-22 13:04:39 -07:00
|
|
|
if (!eina_inlist_find(world->bodies, EINA_INLIST_GET(body)))
|
|
|
|
world->bodies = eina_inlist_append(world->bodies, EINA_INLIST_GET(body));
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
if (eina_error_get())
|
|
|
|
{
|
|
|
|
ERR("Couldn't add body to bodies list.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
2012-08-10 14:03:39 -07:00
|
|
|
|
|
|
|
world->dynamics_world->addRigidBody(ephysics_body_rigid_body_get(body));
|
2012-06-26 15:36:12 -07:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2012-08-22 13:04:39 -07:00
|
|
|
Eina_Bool
|
|
|
|
ephysics_world_soft_body_add(EPhysics_World *world, EPhysics_Body *body)
|
|
|
|
{
|
|
|
|
if (!eina_inlist_find(world->bodies, EINA_INLIST_GET(body)))
|
|
|
|
world->bodies = eina_inlist_append(world->bodies, EINA_INLIST_GET(body));
|
|
|
|
|
|
|
|
if (eina_error_get())
|
|
|
|
{
|
|
|
|
ERR("Couldn't add body to bodies list.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
++world->soft_body_ref;
|
|
|
|
world->dynamics_world->addSoftBody(ephysics_body_soft_body_get(body));
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2012-11-29 10:54:36 -08:00
|
|
|
Eina_List *
|
|
|
|
ephysics_world_constraints_get(EPhysics_World *world)
|
|
|
|
{
|
|
|
|
return world->constraints;
|
|
|
|
}
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
void
|
EPhysics: generic constraint
This patch changes how constraints are created and configured, now we
use a bullet generic implementation which let us operate on the 6
degrees of freedom(linear and angular ones).
We have used 6dof for slider constraint but now we assume 2 types of
constraints, single body - simply ephysics_constraint_add(body) - and a linked
one - ephysics_constraint_linked_add(body1, body2) used to constrain 2 bodies
linked together.
Having said that we introduce the following changes:
+ migrate p2p constraint to 6Dof
We want to have a constraint api generic enouth to allow many different
constraint behaviour, 6Dof was picked to do that, so p2p needs a migration.
+ move ephysics_constraint_slider_* functions
Since the whole constraint infra-sctructure is being migrated to 6Dof the
linear and angular limit functions - previously used only by slider constraint -
now looks more generic enough to be used by constraint in general.
+ add constraint anchor API
Instead of telling the anchoring positioning in the constraint creating we have
set it's default value to the the middle os the body and if the user wants to change
it call ephysics_constraint_anchor_set and reset it.
The ephysics_constraint_anchor_set() considers the canvas coordinate instead of using
the body orientation. So now one can tell a constraints anchor is set to 100, 10, 0
in the canvas coordinate system and not (body_center.x - 20, body_center.y - 5, body_center.z - 1).
+ constraint migrate the bt_constraint
Since we're working only with 6Dof constraints it is reasonable to change the constraints
bt_constraint field to btGeneric6DofConstraint.
+ add 3 axes to constraints
Now constraints API knows about x, y and z axes - linear and angular limiting, anchor
setting and the constraint creation functions are fully supported.
+ constraint calls are renamed
The constraint calls were renamed so ephysics_constraint_p2p_add() now is known as
ephysics_constraint_linked_add() and ephysics_constraint_slider_add() became
ephysics_constraint_add() where the first one is meant for constrain 2 bodies and
the second one for single body constraints.
--This line, and those below, will be ignored--
SVN revision: 79848
2012-11-29 10:51:51 -08:00
|
|
|
ephysics_world_constraint_add(EPhysics_World *world, EPhysics_Constraint *constraint, btGeneric6DofConstraint *bt_constraint)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
EPhysics: generic constraint
This patch changes how constraints are created and configured, now we
use a bullet generic implementation which let us operate on the 6
degrees of freedom(linear and angular ones).
We have used 6dof for slider constraint but now we assume 2 types of
constraints, single body - simply ephysics_constraint_add(body) - and a linked
one - ephysics_constraint_linked_add(body1, body2) used to constrain 2 bodies
linked together.
Having said that we introduce the following changes:
+ migrate p2p constraint to 6Dof
We want to have a constraint api generic enouth to allow many different
constraint behaviour, 6Dof was picked to do that, so p2p needs a migration.
+ move ephysics_constraint_slider_* functions
Since the whole constraint infra-sctructure is being migrated to 6Dof the
linear and angular limit functions - previously used only by slider constraint -
now looks more generic enough to be used by constraint in general.
+ add constraint anchor API
Instead of telling the anchoring positioning in the constraint creating we have
set it's default value to the the middle os the body and if the user wants to change
it call ephysics_constraint_anchor_set and reset it.
The ephysics_constraint_anchor_set() considers the canvas coordinate instead of using
the body orientation. So now one can tell a constraints anchor is set to 100, 10, 0
in the canvas coordinate system and not (body_center.x - 20, body_center.y - 5, body_center.z - 1).
+ constraint migrate the bt_constraint
Since we're working only with 6Dof constraints it is reasonable to change the constraints
bt_constraint field to btGeneric6DofConstraint.
+ add 3 axes to constraints
Now constraints API knows about x, y and z axes - linear and angular limiting, anchor
setting and the constraint creation functions are fully supported.
+ constraint calls are renamed
The constraint calls were renamed so ephysics_constraint_p2p_add() now is known as
ephysics_constraint_linked_add() and ephysics_constraint_slider_add() became
ephysics_constraint_add() where the first one is meant for constrain 2 bodies and
the second one for single body constraints.
--This line, and those below, will be ignored--
SVN revision: 79848
2012-11-29 10:51:51 -08:00
|
|
|
world->dynamics_world->addConstraint(bt_constraint, true);
|
2012-08-16 14:34:44 -07:00
|
|
|
world->constraints = eina_list_append(world->constraints, constraint);
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
EPhysics: generic constraint
This patch changes how constraints are created and configured, now we
use a bullet generic implementation which let us operate on the 6
degrees of freedom(linear and angular ones).
We have used 6dof for slider constraint but now we assume 2 types of
constraints, single body - simply ephysics_constraint_add(body) - and a linked
one - ephysics_constraint_linked_add(body1, body2) used to constrain 2 bodies
linked together.
Having said that we introduce the following changes:
+ migrate p2p constraint to 6Dof
We want to have a constraint api generic enouth to allow many different
constraint behaviour, 6Dof was picked to do that, so p2p needs a migration.
+ move ephysics_constraint_slider_* functions
Since the whole constraint infra-sctructure is being migrated to 6Dof the
linear and angular limit functions - previously used only by slider constraint -
now looks more generic enough to be used by constraint in general.
+ add constraint anchor API
Instead of telling the anchoring positioning in the constraint creating we have
set it's default value to the the middle os the body and if the user wants to change
it call ephysics_constraint_anchor_set and reset it.
The ephysics_constraint_anchor_set() considers the canvas coordinate instead of using
the body orientation. So now one can tell a constraints anchor is set to 100, 10, 0
in the canvas coordinate system and not (body_center.x - 20, body_center.y - 5, body_center.z - 1).
+ constraint migrate the bt_constraint
Since we're working only with 6Dof constraints it is reasonable to change the constraints
bt_constraint field to btGeneric6DofConstraint.
+ add 3 axes to constraints
Now constraints API knows about x, y and z axes - linear and angular limiting, anchor
setting and the constraint creation functions are fully supported.
+ constraint calls are renamed
The constraint calls were renamed so ephysics_constraint_p2p_add() now is known as
ephysics_constraint_linked_add() and ephysics_constraint_slider_add() became
ephysics_constraint_add() where the first one is meant for constrain 2 bodies and
the second one for single body constraints.
--This line, and those below, will be ignored--
SVN revision: 79848
2012-11-29 10:51:51 -08:00
|
|
|
ephysics_world_constraint_del(EPhysics_World *world, EPhysics_Constraint *constraint, btGeneric6DofConstraint *bt_constraint)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
|
|
|
world->dynamics_world->removeConstraint(bt_constraint);
|
2012-08-16 14:34:44 -07:00
|
|
|
world->constraints = eina_list_remove(world->constraints, constraint);
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ephysics_world_init(void)
|
|
|
|
{
|
|
|
|
if (++_ephysics_world_init_count != 1)
|
|
|
|
return _ephysics_world_init_count;
|
|
|
|
|
|
|
|
gContactProcessedCallback = _ephysics_world_contact_processed_cb;
|
|
|
|
|
|
|
|
INF("EPhysics World initialized.");
|
|
|
|
|
|
|
|
return _ephysics_world_init_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ephysics_world_shutdown(void)
|
|
|
|
{
|
|
|
|
if (--_ephysics_world_init_count != 0)
|
|
|
|
return _ephysics_world_init_count;
|
|
|
|
|
|
|
|
if (_anim_simulate)
|
|
|
|
{
|
|
|
|
ecore_animator_del(_anim_simulate);
|
|
|
|
_anim_simulate = NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-10 14:03:01 -07:00
|
|
|
while (_worlds)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
2012-08-10 14:03:01 -07:00
|
|
|
EPhysics_World *world = EINA_INLIST_CONTAINER_GET(
|
|
|
|
_worlds, EPhysics_World);
|
2012-06-26 15:36:12 -07:00
|
|
|
ephysics_world_del(world);
|
|
|
|
}
|
|
|
|
|
|
|
|
_worlds_running = 0;
|
|
|
|
|
|
|
|
INF("EPhysics World shutdown.");
|
|
|
|
|
|
|
|
return _ephysics_world_init_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ephysics_world_boundary_set(EPhysics_World *world, EPhysics_World_Boundary boundary, EPhysics_Body *body)
|
|
|
|
{
|
|
|
|
world->boundaries[boundary] = body;
|
|
|
|
}
|
|
|
|
|
|
|
|
EPhysics_Body *
|
|
|
|
ephysics_world_boundary_get(const EPhysics_World *world, EPhysics_World_Boundary boundary)
|
|
|
|
{
|
|
|
|
return world->boundaries[boundary];
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
static void
|
|
|
|
_th_simulate(void *data, Ecore_Thread *th)
|
|
|
|
{
|
|
|
|
EPhysics_World *world = (EPhysics_World *) data;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
double time_now, delta;
|
|
|
|
EPhysics_Body *body;
|
|
|
|
|
|
|
|
eina_condition_wait(&world->condition);
|
|
|
|
if (ecore_thread_check(th))
|
|
|
|
{
|
|
|
|
INF("Thread canceled by main loop thread");
|
|
|
|
eina_lock_release(&world->mutex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->pending_ticks++;
|
|
|
|
world->cur_th = th;
|
|
|
|
|
|
|
|
EINA_INLIST_FOREACH(world->bodies, body)
|
2012-10-16 16:18:21 -07:00
|
|
|
{
|
|
|
|
ephysics_body_forces_apply(body);
|
|
|
|
if (body->dragging_data.dragging)
|
|
|
|
ephysics_body_soft_body_dragging_apply(body);
|
2012-11-23 13:43:32 -08:00
|
|
|
|
|
|
|
if (body->bending_constraints)
|
|
|
|
ephysics_body_soft_body_bending_constraints_generate(body);
|
2012-10-16 16:18:21 -07:00
|
|
|
}
|
2012-10-04 15:38:06 -07:00
|
|
|
|
|
|
|
time_now = ecore_time_get();
|
|
|
|
delta = time_now - world->last_update;
|
|
|
|
world->last_update = time_now;
|
|
|
|
|
|
|
|
gDeactivationTime = world->max_sleeping_time;
|
|
|
|
|
|
|
|
if (world->soft_body_ref)
|
|
|
|
{
|
|
|
|
world->dynamics_world->stepSimulation(delta, world->max_sub_steps,
|
|
|
|
world->fixed_time_step);
|
|
|
|
world->world_info->m_sparsesdf.GarbageCollect();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
((btDiscreteDynamicsWorld *)world->dynamics_world)->stepSimulation(
|
|
|
|
delta, world->max_sub_steps, world->fixed_time_step);
|
|
|
|
|
2012-10-04 15:40:52 -07:00
|
|
|
_ephysics_world_tick_dispatch(world);
|
2012-10-04 15:38:06 -07:00
|
|
|
world->pending_ticks--;
|
|
|
|
eina_lock_release(&world->mutex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-01-03 14:10:40 -08:00
|
|
|
_th_msg_cb(void *data, Ecore_Thread *th EINA_UNUSED, void *msg_data)
|
2012-10-04 15:38:06 -07:00
|
|
|
{
|
|
|
|
EPhysics_World *world = (EPhysics_World *) data;
|
|
|
|
Simulation_Msg *msg = (Simulation_Msg *) msg_data;
|
|
|
|
|
|
|
|
if (msg->tick)
|
|
|
|
_ephysics_world_tick(world->dynamics_world);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ephysics_body_contact_processed(msg->body_0, msg->body_1, msg->pos_a);
|
|
|
|
ephysics_body_contact_processed(msg->body_1, msg->body_0, msg->pos_b);
|
|
|
|
}
|
|
|
|
free(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_th_end_cb(void *data, Ecore_Thread *th)
|
|
|
|
{
|
|
|
|
EPhysics_World *world = (EPhysics_World *) data;
|
|
|
|
INF("World %p simulation thread %p end", world, th);
|
|
|
|
world->simulation_th = NULL;
|
|
|
|
_ephysics_world_free(world);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_th_cancel_cb(void *data, Ecore_Thread *th)
|
|
|
|
{
|
|
|
|
EPhysics_World *world = (EPhysics_World *) data;
|
|
|
|
INF("World %p simulation thread %p canceled", world, th);
|
|
|
|
world->simulation_th = NULL;
|
|
|
|
_ephysics_world_free(world);
|
|
|
|
}
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
EAPI EPhysics_World *
|
|
|
|
ephysics_world_new(void)
|
|
|
|
{
|
|
|
|
EPhysics_World *world;
|
|
|
|
|
|
|
|
world = (EPhysics_World *) calloc(1, sizeof(EPhysics_World));
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Couldn't create a new world instance.");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->camera = ephysics_camera_add(world);
|
|
|
|
if (!world->camera)
|
|
|
|
{
|
|
|
|
ERR("Couldn't create a camera for this world.");
|
|
|
|
goto no_camera;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->broadphase = new btDbvtBroadphase();
|
|
|
|
if (!world->broadphase)
|
|
|
|
{
|
|
|
|
ERR("Couldn't set broadphase.");
|
|
|
|
goto no_broadphase;
|
|
|
|
}
|
|
|
|
|
2012-08-22 13:04:39 -07:00
|
|
|
world->collision = new btSoftBodyRigidBodyCollisionConfiguration();
|
2012-06-26 15:36:12 -07:00
|
|
|
if (!world->collision)
|
|
|
|
{
|
|
|
|
ERR("Couldn't configure collision.");
|
|
|
|
goto no_collision;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->dispatcher = new btCollisionDispatcher(world->collision);
|
|
|
|
if (!world->dispatcher)
|
|
|
|
{
|
|
|
|
ERR("Couldn't create dispatcher.");
|
|
|
|
goto no_dispatcher;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->solver = new btSequentialImpulseConstraintSolver;
|
|
|
|
if (!world->solver)
|
|
|
|
{
|
|
|
|
ERR("Couldn't create solver.");
|
|
|
|
goto no_solver;
|
|
|
|
}
|
|
|
|
|
2012-08-22 13:04:39 -07:00
|
|
|
world->soft_solver = new btDefaultSoftBodySolver();
|
|
|
|
if (!world->soft_solver)
|
|
|
|
{
|
|
|
|
ERR("Couldn't create soft body solver.");
|
|
|
|
goto no_soft_solver;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->dynamics_world = new btSoftRigidDynamicsWorld(
|
2012-06-26 15:36:12 -07:00
|
|
|
world->dispatcher, world->broadphase, world->solver,
|
2012-08-22 13:04:39 -07:00
|
|
|
world->collision, world->soft_solver);
|
2012-06-26 15:36:12 -07:00
|
|
|
if (!world->dynamics_world)
|
|
|
|
{
|
|
|
|
ERR("Couldn't create dynamic world.");
|
|
|
|
goto no_world;
|
|
|
|
}
|
|
|
|
|
2012-08-22 13:04:39 -07:00
|
|
|
world->world_info = new btSoftBodyWorldInfo();
|
|
|
|
if (!world->world_info)
|
|
|
|
{
|
|
|
|
ERR("Couldn't create soft body world info.");
|
|
|
|
goto no_world_info;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->world_info->m_gravity = DEFAULT_GRAVITY;
|
|
|
|
world->world_info->m_broadphase = world->broadphase;
|
|
|
|
world->world_info->m_dispatcher = world->dispatcher;
|
|
|
|
world->world_info->m_sparsesdf.Initialize();
|
|
|
|
|
2012-08-10 14:03:01 -07:00
|
|
|
_worlds = eina_inlist_append(_worlds, EINA_INLIST_GET(world));
|
2012-06-26 15:36:12 -07:00
|
|
|
if (eina_error_get())
|
|
|
|
{
|
|
|
|
ERR("Couldn't add world to worlds list.");
|
|
|
|
goto no_list;
|
|
|
|
}
|
2012-10-04 15:38:06 -07:00
|
|
|
world->simulation_th = ecore_thread_feedback_run(
|
|
|
|
_th_simulate, _th_msg_cb, _th_end_cb, _th_cancel_cb, world, EINA_TRUE);
|
|
|
|
if (!world->simulation_th)
|
|
|
|
{
|
|
|
|
ERR("Failed to create simulation thread.");
|
|
|
|
goto no_thread;
|
|
|
|
}
|
|
|
|
eina_lock_new(&world->mutex);
|
|
|
|
eina_condition_new(&world->condition, &world->mutex);
|
2012-06-26 15:36:12 -07:00
|
|
|
|
2012-07-05 15:53:14 -07:00
|
|
|
world->dynamics_world->getSolverInfo().m_solverMode ^=
|
|
|
|
EPHYSICS_WORLD_SOLVER_SIMD;
|
2012-08-22 13:04:39 -07:00
|
|
|
world->dynamics_world->setGravity(DEFAULT_GRAVITY);
|
2012-07-27 07:49:53 -07:00
|
|
|
|
2012-10-04 15:38:00 -07:00
|
|
|
world->filter_cb = new _ephysics_world_ovelap_filter_cb();
|
|
|
|
if (!world->filter_cb)
|
2012-07-27 07:49:53 -07:00
|
|
|
INF("Couldn't initialize the collision filter.");
|
|
|
|
else
|
2012-10-04 15:38:00 -07:00
|
|
|
world->dynamics_world->getPairCache()->setOverlapFilterCallback(
|
2012-10-25 14:55:23 -07:00
|
|
|
world->filter_cb);
|
2012-07-27 07:49:53 -07:00
|
|
|
|
2012-10-30 11:31:32 -07:00
|
|
|
world->light.lr = 255;
|
|
|
|
world->light.lg = 255;
|
|
|
|
world->light.lb = 255;
|
|
|
|
world->light.lz = -200;
|
|
|
|
|
2012-10-25 14:55:23 -07:00
|
|
|
world->stacking = EINA_TRUE;
|
2012-06-26 15:36:12 -07:00
|
|
|
world->rate = 30;
|
2012-07-31 12:55:52 -07:00
|
|
|
world->max_sub_steps = 3;
|
|
|
|
world->fixed_time_step = 1/60.f;
|
2012-06-26 15:36:12 -07:00
|
|
|
world->dynamics_world->setInternalTickCallback(_ephysics_world_tick_cb,
|
|
|
|
(void *) world);
|
|
|
|
|
2012-07-27 07:48:59 -07:00
|
|
|
world->max_sleeping_time = 2.0;
|
2012-06-26 15:36:12 -07:00
|
|
|
world->running = EINA_TRUE;
|
|
|
|
world->last_update = ecore_time_get();
|
|
|
|
_worlds_running++;
|
|
|
|
if (!_anim_simulate)
|
2012-08-21 10:47:29 -07:00
|
|
|
_anim_simulate = ecore_animator_add(_simulate_worlds, NULL);
|
2012-06-26 15:36:12 -07:00
|
|
|
|
2012-10-04 15:38:11 -07:00
|
|
|
ephysics_dom_count_inc();
|
2012-07-03 16:21:11 -07:00
|
|
|
INF("World %p added.", world);
|
2012-06-26 15:36:12 -07:00
|
|
|
return world;
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
no_thread:
|
|
|
|
_worlds = eina_inlist_remove(_worlds, EINA_INLIST_GET(world));
|
2012-06-26 15:36:12 -07:00
|
|
|
no_list:
|
2012-08-22 13:04:39 -07:00
|
|
|
delete world->world_info;
|
|
|
|
no_world_info:
|
2012-06-26 15:36:12 -07:00
|
|
|
delete world->dynamics_world;
|
|
|
|
no_world:
|
2012-08-22 13:04:39 -07:00
|
|
|
delete world->soft_solver;
|
|
|
|
no_soft_solver:
|
2012-06-26 15:36:12 -07:00
|
|
|
delete world->solver;
|
|
|
|
no_solver:
|
|
|
|
delete world->dispatcher;
|
|
|
|
no_dispatcher:
|
|
|
|
delete world->collision;
|
|
|
|
no_collision:
|
|
|
|
delete world->broadphase;
|
|
|
|
no_broadphase:
|
|
|
|
ephysics_camera_del(world->camera);
|
|
|
|
no_camera:
|
|
|
|
free(world);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
2012-10-04 15:38:06 -07:00
|
|
|
ephysics_world_serialize(EPhysics_World *world, const char *path)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
|
|
|
btDefaultSerializer *serializer;
|
|
|
|
FILE *file;
|
|
|
|
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
WRN("Could not serialize, world not provided.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_take(&world->mutex);
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
file = fopen(path, "wb");
|
|
|
|
if (!file)
|
|
|
|
{
|
|
|
|
WRN("Could not serialize, could not open file: %s", path);
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_release(&world->mutex);
|
2012-06-26 15:36:12 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
serializer = new btDefaultSerializer();
|
|
|
|
world->dynamics_world->serialize(serializer);
|
|
|
|
|
|
|
|
if (!fwrite(serializer->getBufferPointer(),
|
|
|
|
serializer->getCurrentBufferSize(), 1, file))
|
|
|
|
{
|
|
|
|
WRN("Problems on writing to: %s.", path);
|
|
|
|
fclose(file);
|
|
|
|
delete serializer;
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_release(&world->mutex);
|
2012-06-26 15:36:12 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(file);
|
|
|
|
delete serializer;
|
|
|
|
|
2012-07-03 16:21:11 -07:00
|
|
|
INF("Serialization of world %p written to file: %s.", world, path);
|
2012-06-26 15:36:12 -07:00
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_release(&world->mutex);
|
2012-06-26 15:36:12 -07:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
static void
|
|
|
|
_ephysics_world_running_set(EPhysics_World *world, Eina_Bool running)
|
|
|
|
{
|
|
|
|
if ((!!running) == world->running) return;
|
|
|
|
|
|
|
|
world->running = !!running;
|
|
|
|
|
|
|
|
if (world->running)
|
|
|
|
{
|
|
|
|
world->last_update = ecore_time_get();
|
|
|
|
_worlds_running++;
|
|
|
|
INF("World unpaused.");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_worlds_running--;
|
|
|
|
INF("World paused.");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!_worlds_running)
|
|
|
|
{
|
|
|
|
if (_anim_simulate)
|
|
|
|
{
|
|
|
|
ecore_animator_del(_anim_simulate);
|
|
|
|
_anim_simulate = NULL;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_anim_simulate)
|
|
|
|
return;
|
|
|
|
|
|
|
|
_anim_simulate = ecore_animator_add(_simulate_worlds, NULL);
|
|
|
|
}
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
EAPI void
|
|
|
|
ephysics_world_del(EPhysics_World *world)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't delete world, it wasn't provided.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-10 14:03:29 -07:00
|
|
|
if (world->deleted) return;
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_take(&world->mutex);
|
|
|
|
|
2012-08-10 14:03:29 -07:00
|
|
|
world->deleted = EINA_TRUE;
|
2012-08-10 14:04:22 -07:00
|
|
|
_ephysics_world_event_callback_call(world, EPHYSICS_CALLBACK_WORLD_DEL,
|
|
|
|
NULL);
|
2012-10-04 15:38:06 -07:00
|
|
|
_ephysics_world_running_set(world, EINA_FALSE);
|
2012-06-26 15:36:12 -07:00
|
|
|
|
2012-08-10 14:03:29 -07:00
|
|
|
if (_worlds_walking > 0)
|
2012-08-10 14:03:06 -07:00
|
|
|
{
|
2012-08-10 14:03:29 -07:00
|
|
|
_worlds_to_delete = eina_list_append(_worlds_to_delete, world);
|
|
|
|
INF("World %p marked to delete.", world);
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_release(&world->mutex);
|
2012-08-10 14:03:29 -07:00
|
|
|
return;
|
2012-08-10 14:03:06 -07:00
|
|
|
}
|
2012-06-26 15:36:12 -07:00
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_release(&world->mutex);
|
|
|
|
_ephysics_world_th_cancel(world);
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ephysics_world_running_set(EPhysics_World *world, Eina_Bool running)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't (un)pause world, it wasn't provided.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_take(&world->mutex);
|
|
|
|
_ephysics_world_running_set(world, running);
|
|
|
|
eina_lock_release(&world->mutex);
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
ephysics_world_running_get(const EPhysics_World *world)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("No world, no running status for you.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->running;
|
|
|
|
}
|
|
|
|
|
2012-07-27 07:48:59 -07:00
|
|
|
EAPI void
|
|
|
|
ephysics_world_max_sleeping_time_set(EPhysics_World *world, double sleeping_time)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't set the world's max sleeping time, world is null.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_take(&world->mutex);
|
2012-07-27 07:48:59 -07:00
|
|
|
world->max_sleeping_time = sleeping_time;
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_release(&world->mutex);
|
2012-07-27 07:48:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI double
|
|
|
|
ephysics_world_max_sleeping_time_get(const EPhysics_World *world)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't get the world's max sleeping time, world is null.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->max_sleeping_time;
|
|
|
|
}
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
EAPI void
|
2012-10-10 12:17:44 -07:00
|
|
|
ephysics_world_gravity_set(EPhysics_World *world, double gx, double gy, double gz)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
2012-10-09 13:00:36 -07:00
|
|
|
EPhysics_Body *bd;
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't set gravity, no world provided.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_take(&world->mutex);
|
2012-10-09 13:00:36 -07:00
|
|
|
EINA_INLIST_FOREACH(world->bodies, bd)
|
|
|
|
ephysics_body_activate(bd, EINA_TRUE);
|
2012-10-10 12:17:44 -07:00
|
|
|
_ephysics_world_gravity_set(world, gx, gy, gz, world->rate);
|
|
|
|
DBG("World %p gravity set to X:%lf, Y:%lf, Z: %lf.", world, gx, gy, gz);
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_release(&world->mutex);
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
2012-07-03 16:24:27 -07:00
|
|
|
EAPI void
|
|
|
|
ephysics_world_constraint_solver_iterations_set(EPhysics_World *world, int iterations)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't set constraint solver iterations, world is null.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_take(&world->mutex);
|
2012-07-03 16:24:27 -07:00
|
|
|
world->dynamics_world->getSolverInfo().m_numIterations = iterations;
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_release(&world->mutex);
|
2012-07-03 16:24:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI int
|
2012-07-06 07:36:40 -07:00
|
|
|
ephysics_world_constraint_solver_iterations_get(const EPhysics_World *world)
|
2012-07-03 16:24:27 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't get constraint solver iterations, world is null.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->dynamics_world->getSolverInfo().m_numIterations;
|
|
|
|
}
|
|
|
|
|
2012-07-05 15:53:14 -07:00
|
|
|
EAPI void
|
|
|
|
ephysics_world_constraint_solver_mode_enable_set(EPhysics_World *world, EPhysics_World_Solver_Mode solver_mode, Eina_Bool enable)
|
|
|
|
{
|
|
|
|
int current_solver_mode;
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't enable/disable constraint solver mode, world is null.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_take(&world->mutex);
|
2012-07-05 15:53:14 -07:00
|
|
|
current_solver_mode = world->dynamics_world->getSolverInfo().m_solverMode;
|
|
|
|
if ((enable && !(current_solver_mode & solver_mode)) ||
|
|
|
|
(!enable && (current_solver_mode & solver_mode)))
|
|
|
|
world->dynamics_world->getSolverInfo().m_solverMode ^= solver_mode;
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_release(&world->mutex);
|
2012-07-05 15:53:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
2012-07-06 07:36:40 -07:00
|
|
|
ephysics_world_constraint_solver_mode_enable_get(const EPhysics_World *world, EPhysics_World_Solver_Mode solver_mode)
|
2012-07-05 15:53:14 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't get constraint solver mode status, world is null.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->dynamics_world->getSolverInfo().m_solverMode & solver_mode;
|
|
|
|
}
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
EAPI void
|
2012-10-10 12:17:44 -07:00
|
|
|
ephysics_world_gravity_get(const EPhysics_World *world, double *gx, double *gy, double *gz)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
|
|
|
btVector3 vector;
|
|
|
|
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("No world, can't get gravity.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector = world->dynamics_world->getGravity();
|
|
|
|
|
2012-07-02 19:17:55 -07:00
|
|
|
if (gx) *gx = vector.x() * world->rate;
|
|
|
|
if (gy) *gy = -vector.y() * world->rate;
|
2012-10-10 12:17:44 -07:00
|
|
|
if (gz) *gz = vector.z() * world->rate;
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ephysics_world_rate_set(EPhysics_World *world, double rate)
|
|
|
|
{
|
2012-08-16 14:35:20 -07:00
|
|
|
EPhysics_Body *body;
|
2012-10-10 12:17:44 -07:00
|
|
|
double gx, gy, gz;
|
2012-08-16 14:35:20 -07:00
|
|
|
void *constraint;
|
|
|
|
Eina_List *l;
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("No world, can't set rate.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rate <= 0)
|
|
|
|
{
|
|
|
|
ERR("Rate should be a positive value. Keeping the old value: %lf.",
|
|
|
|
world->rate);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_take(&world->mutex);
|
2012-08-16 14:35:20 -07:00
|
|
|
/* Force to recalculate sizes, velocities and accelerations with new rate */
|
2012-10-10 12:17:44 -07:00
|
|
|
ephysics_world_gravity_get(world, &gx, &gy, &gz);
|
|
|
|
_ephysics_world_gravity_set(world, gx, gy, gz, rate);
|
2012-08-16 14:35:20 -07:00
|
|
|
|
|
|
|
EINA_INLIST_FOREACH(world->bodies, body)
|
|
|
|
ephysics_body_recalc(body, rate);
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(world->constraints, l, constraint)
|
|
|
|
ephysics_constraint_recalc((EPhysics_Constraint *)constraint, rate);
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
world->rate = rate;
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_release(&world->mutex);
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI double
|
|
|
|
ephysics_world_rate_get(const EPhysics_World *world)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("No world, can't get rate.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->rate;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI EPhysics_Camera *
|
|
|
|
ephysics_world_camera_get(const EPhysics_World *world)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("No world, no camera for you.");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->camera;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
2012-07-02 19:09:34 -07:00
|
|
|
ephysics_world_event_callback_add(EPhysics_World *world, EPhysics_Callback_World_Type type, EPhysics_World_Event_Cb func, const void *data)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
|
|
|
EPhysics_World_Callback *cb;
|
|
|
|
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't set world event callback, world is null.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!func)
|
|
|
|
{
|
|
|
|
ERR("Can't set world event callback, function is null.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-02 19:09:34 -07:00
|
|
|
if ((type < 0) || (type >= EPHYSICS_CALLBACK_WORLD_LAST))
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
|
|
|
ERR("Can't set world event callback, callback type is wrong.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-10 14:04:42 -07:00
|
|
|
cb = (EPhysics_World_Callback *)calloc(1, sizeof(EPhysics_World_Callback));
|
2012-06-26 15:36:12 -07:00
|
|
|
if (!cb)
|
|
|
|
{
|
|
|
|
ERR("Can't set world event callback, can't create cb instance.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cb->func = func;
|
|
|
|
cb->type = type;
|
|
|
|
cb->data = (void *) data;
|
|
|
|
|
|
|
|
world->callbacks = eina_inlist_append(world->callbacks, EINA_INLIST_GET(cb));
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void *
|
2012-07-02 19:09:34 -07:00
|
|
|
ephysics_world_event_callback_del(EPhysics_World *world, EPhysics_Callback_World_Type type, EPhysics_World_Event_Cb func)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
|
|
|
EPhysics_World_Callback *cb;
|
2012-08-10 14:04:22 -07:00
|
|
|
void *cb_data = NULL;
|
2012-06-26 15:36:12 -07:00
|
|
|
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't delete world event callback, world is null.");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EINA_INLIST_FOREACH(world->callbacks, cb)
|
|
|
|
{
|
2012-08-10 14:04:22 -07:00
|
|
|
if ((cb->type != type) || (cb->func != func))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cb_data = cb->data;
|
|
|
|
_ephysics_world_event_callback_del(world, cb);
|
|
|
|
break;
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
2012-08-10 14:04:22 -07:00
|
|
|
return cb_data;
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
2012-07-02 19:09:12 -07:00
|
|
|
EAPI void *
|
2012-07-02 19:09:34 -07:00
|
|
|
ephysics_world_event_callback_del_full(EPhysics_World *world, EPhysics_Callback_World_Type type, EPhysics_World_Event_Cb func, void *data)
|
2012-07-02 19:09:12 -07:00
|
|
|
{
|
|
|
|
EPhysics_World_Callback *cb;
|
2012-08-10 14:04:22 -07:00
|
|
|
void *cb_data = NULL;
|
2012-07-02 19:09:12 -07:00
|
|
|
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't delete world event callback, world is null.");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EINA_INLIST_FOREACH(world->callbacks, cb)
|
|
|
|
{
|
2012-08-10 14:04:22 -07:00
|
|
|
if ((cb->type != type) || (cb->func != func) || (cb->data != data))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cb_data = cb->data;
|
|
|
|
_ephysics_world_event_callback_del(world, cb);
|
|
|
|
break;
|
2012-07-02 19:09:12 -07:00
|
|
|
}
|
|
|
|
|
2012-08-10 14:04:22 -07:00
|
|
|
return cb_data;
|
2012-07-02 19:09:12 -07:00
|
|
|
}
|
|
|
|
|
2012-08-10 14:03:06 -07:00
|
|
|
EAPI Eina_List *
|
2012-06-26 15:36:12 -07:00
|
|
|
ephysics_world_bodies_get(const EPhysics_World *world)
|
|
|
|
{
|
2012-08-10 14:03:06 -07:00
|
|
|
Eina_List *list = NULL;
|
|
|
|
EPhysics_Body *body;
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Couldn't get the bodies list, no world provided.");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-10 14:03:06 -07:00
|
|
|
EINA_INLIST_FOREACH(world->bodies, body)
|
|
|
|
list = eina_list_append(list, body);
|
|
|
|
|
|
|
|
return list;
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
2012-10-15 14:54:29 -07:00
|
|
|
ephysics_world_render_geometry_set(EPhysics_World *world, Evas_Coord x, Evas_Coord y, Evas_Coord z, Evas_Coord w, Evas_Coord h, Evas_Coord d)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't set geometry, world wasn't provided.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-15 14:54:29 -07:00
|
|
|
if ((w <= 0) || (h <= 0) || (d <= 0))
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
|
|
|
ERR("Invalid width or height sizes. They must to be positive values.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-15 14:54:29 -07:00
|
|
|
world->geometry.x = x;
|
|
|
|
world->geometry.y = y;
|
|
|
|
world->geometry.z = z;
|
|
|
|
world->geometry.w = w;
|
|
|
|
world->geometry.h = h;
|
|
|
|
world->geometry.d = d;
|
2012-06-26 15:36:12 -07:00
|
|
|
|
2012-11-28 13:47:47 -08:00
|
|
|
INF("World %p render geometry set: x=%i y=%i z=%i w=%i h=%i d=%i",
|
|
|
|
world, x, y, z, w, h, d);
|
|
|
|
|
2012-10-18 16:55:45 -07:00
|
|
|
ephysics_camera_perspective_set(world->camera, x + w / 2, y + h / 2,
|
|
|
|
z + d / 2, 10 * (z + d));
|
2012-10-18 16:27:26 -07:00
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
ephysics_body_world_boundaries_resize(world);
|
2012-07-27 07:50:03 -07:00
|
|
|
ephysics_camera_position_set(world->camera, x, y);
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
2012-10-15 14:54:29 -07:00
|
|
|
ephysics_world_render_geometry_get(const EPhysics_World *world, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z, Evas_Coord *w, Evas_Coord *h, Evas_Coord *d)
|
2012-06-26 15:36:12 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't get geometry, world is null.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-15 14:54:29 -07:00
|
|
|
if (x) *x = world->geometry.x;
|
|
|
|
if (y) *y = world->geometry.y;
|
|
|
|
if (z) *z = world->geometry.z;
|
|
|
|
if (w) *w = world->geometry.w;
|
|
|
|
if (h) *h = world->geometry.h;
|
|
|
|
if (d) *d = world->geometry.d;
|
2012-06-26 15:36:12 -07:00
|
|
|
}
|
|
|
|
|
2012-06-29 15:24:33 -07:00
|
|
|
EAPI void
|
|
|
|
ephysics_world_linear_slop_set(EPhysics_World *world, double linear_slop)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't set linear slop, world is null.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_take(&world->mutex);
|
2012-06-29 15:24:33 -07:00
|
|
|
world->dynamics_world->getSolverInfo().m_linearSlop = btScalar(linear_slop);
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_release(&world->mutex);
|
2012-06-29 15:24:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI double
|
2012-07-06 07:36:40 -07:00
|
|
|
ephysics_world_linear_slop_get(const EPhysics_World *world)
|
2012-06-29 15:24:33 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't get linear slop, world is null.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->dynamics_world->getSolverInfo().m_linearSlop;
|
|
|
|
}
|
|
|
|
|
2012-07-03 16:20:49 -07:00
|
|
|
EAPI void
|
|
|
|
ephysics_world_bodies_outside_top_autodel_set(EPhysics_World *world, Eina_Bool autodel)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't set autodelete mode, world is null.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->outside_top = !!autodel;
|
|
|
|
world->outside_autodel = world->outside_top || world->outside_bottom ||
|
2012-10-15 14:54:35 -07:00
|
|
|
world->outside_left || world->outside_right ||
|
|
|
|
world->outside_front || world->outside_back;
|
2012-07-03 16:20:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
2012-07-06 07:36:40 -07:00
|
|
|
ephysics_world_bodies_outside_top_autodel_get(const EPhysics_World *world)
|
2012-07-03 16:20:49 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't get autodelete mode, world is null.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->outside_top;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ephysics_world_bodies_outside_bottom_autodel_set(EPhysics_World *world, Eina_Bool autodel)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't set autodelete mode, world is null.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->outside_bottom = !!autodel;
|
|
|
|
world->outside_autodel = world->outside_top || world->outside_bottom ||
|
2012-10-15 14:54:35 -07:00
|
|
|
world->outside_left || world->outside_right ||
|
|
|
|
world->outside_front || world->outside_back;
|
2012-07-03 16:20:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
2012-07-06 07:36:40 -07:00
|
|
|
ephysics_world_bodies_outside_bottom_autodel_get(const EPhysics_World *world)
|
2012-07-03 16:20:49 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't get autodelete mode, world is null.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->outside_bottom;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ephysics_world_bodies_outside_left_autodel_set(EPhysics_World *world, Eina_Bool autodel)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't set autodelete mode, world is null.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->outside_left = !!autodel;
|
|
|
|
world->outside_autodel = world->outside_top || world->outside_bottom ||
|
2012-10-15 14:54:35 -07:00
|
|
|
world->outside_left || world->outside_right ||
|
|
|
|
world->outside_front || world->outside_back;
|
2012-07-03 16:20:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
2012-07-06 07:36:40 -07:00
|
|
|
ephysics_world_bodies_outside_left_autodel_get(const EPhysics_World *world)
|
2012-07-03 16:20:49 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't get autodelete mode, world is null.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->outside_left;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ephysics_world_bodies_outside_right_autodel_set(EPhysics_World *world, Eina_Bool autodel)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't set autodelete mode, world is null.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->outside_right = !!autodel;
|
|
|
|
world->outside_autodel = world->outside_top || world->outside_bottom ||
|
2012-10-15 14:54:35 -07:00
|
|
|
world->outside_left || world->outside_right ||
|
|
|
|
world->outside_front || world->outside_back;
|
2012-07-03 16:20:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
2012-07-06 07:36:40 -07:00
|
|
|
ephysics_world_bodies_outside_right_autodel_get(const EPhysics_World *world)
|
2012-07-03 16:20:49 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't get autodelete mode, world is null.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->outside_right;
|
|
|
|
}
|
|
|
|
|
2012-10-15 14:54:35 -07:00
|
|
|
EAPI void
|
|
|
|
ephysics_world_bodies_outside_front_autodel_set(EPhysics_World *world, Eina_Bool autodel)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't set autodelete mode, world is null.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->outside_front = !!autodel;
|
|
|
|
world->outside_autodel = world->outside_top || world->outside_bottom ||
|
|
|
|
world->outside_left || world->outside_right ||
|
|
|
|
world->outside_front || world->outside_back;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
ephysics_world_bodies_outside_front_autodel_get(const EPhysics_World *world)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't get autodelete mode, world is null.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->outside_front;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ephysics_world_bodies_outside_back_autodel_set(EPhysics_World *world, Eina_Bool autodel)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't set autodelete mode, world is null.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->outside_back = !!autodel;
|
|
|
|
world->outside_autodel = world->outside_top || world->outside_bottom ||
|
|
|
|
world->outside_left || world->outside_right ||
|
|
|
|
world->outside_front || world->outside_back;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
ephysics_world_bodies_outside_back_autodel_get(const EPhysics_World *world)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't get autodelete mode, world is null.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->outside_back;
|
|
|
|
}
|
|
|
|
|
2012-07-31 12:55:52 -07:00
|
|
|
EAPI Eina_Bool
|
2012-07-06 07:36:40 -07:00
|
|
|
ephysics_world_bodies_outside_autodel_get(const EPhysics_World *world)
|
2012-07-03 16:20:49 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't get autodelete mode, world is null.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->outside_autodel;
|
|
|
|
}
|
|
|
|
|
2012-07-31 12:55:52 -07:00
|
|
|
EAPI void
|
|
|
|
ephysics_world_simulation_set(EPhysics_World *world, double fixed_time_step, int max_sub_steps)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't set simulation, no world provided.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (max_sub_steps < 1)
|
|
|
|
{
|
|
|
|
ERR("At least one sub step for simulation is required.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ecore_animator_frametime_get() >= max_sub_steps * fixed_time_step)
|
|
|
|
{
|
|
|
|
ERR("Assure frametime < max sub steps * fixed time step.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_take(&world->mutex);
|
2012-07-31 12:55:52 -07:00
|
|
|
world->max_sub_steps = max_sub_steps;
|
|
|
|
world->fixed_time_step = fixed_time_step;
|
|
|
|
|
|
|
|
DBG("World %p simulation set to fixed time step: %lf, max substeps:%i.",
|
|
|
|
world, fixed_time_step, max_sub_steps);
|
2012-10-04 15:38:06 -07:00
|
|
|
eina_lock_release(&world->mutex);
|
2012-07-31 12:55:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ephysics_world_simulation_get(const EPhysics_World *world, double *fixed_time_step, int *max_sub_steps)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("No world, can't get simulation configuration.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fixed_time_step) *fixed_time_step = world->fixed_time_step;
|
|
|
|
if (max_sub_steps) *max_sub_steps = world->max_sub_steps;
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:38:06 -07:00
|
|
|
void
|
|
|
|
ephysics_world_lock_take(EPhysics_World *world)
|
|
|
|
{
|
|
|
|
eina_lock_take(&world->mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ephysics_world_lock_release(EPhysics_World *world)
|
|
|
|
{
|
|
|
|
eina_lock_release(&world->mutex);
|
|
|
|
}
|
|
|
|
|
2012-10-10 13:32:08 -07:00
|
|
|
EAPI void
|
2012-10-30 11:31:32 -07:00
|
|
|
ephysics_world_point_light_position_set(EPhysics_World *world, Evas_Coord lx, Evas_Coord ly, Evas_Coord lz)
|
2012-10-10 13:32:08 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
2012-10-30 11:31:32 -07:00
|
|
|
ERR("No world, can't set light properties.");
|
2012-10-10 13:32:08 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-30 11:31:32 -07:00
|
|
|
world->light.lx = lx;
|
|
|
|
world->light.ly = ly;
|
|
|
|
world->light.lz = lz;
|
2012-12-03 13:29:03 -08:00
|
|
|
world->force_update = EINA_TRUE;
|
2012-10-30 11:31:32 -07:00
|
|
|
}
|
2012-10-10 13:32:08 -07:00
|
|
|
|
2012-10-30 11:31:32 -07:00
|
|
|
EAPI void
|
|
|
|
ephysics_world_point_light_color_set(EPhysics_World *world, int lr, int lg, int lb)
|
|
|
|
{
|
|
|
|
if (!world)
|
2012-10-10 13:32:08 -07:00
|
|
|
{
|
2012-10-30 11:31:32 -07:00
|
|
|
ERR("No world, can't set light properties.");
|
2012-10-10 13:32:08 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-30 11:31:32 -07:00
|
|
|
world->light.lr = lr;
|
|
|
|
world->light.lg = lg;
|
|
|
|
world->light.lb = lb;
|
2012-12-03 13:29:03 -08:00
|
|
|
world->force_update = EINA_TRUE;
|
2012-10-10 13:32:08 -07:00
|
|
|
}
|
|
|
|
|
2012-10-30 11:31:32 -07:00
|
|
|
EAPI void
|
|
|
|
ephysics_world_ambient_light_color_set(EPhysics_World *world, int ar, int ag, int ab)
|
2012-10-10 13:32:08 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
2012-10-30 11:31:32 -07:00
|
|
|
ERR("No world, can't set light properties.");
|
|
|
|
return;
|
2012-10-10 13:32:08 -07:00
|
|
|
}
|
|
|
|
|
2012-10-30 11:31:32 -07:00
|
|
|
world->light.ar = ar;
|
|
|
|
world->light.ag = ag;
|
|
|
|
world->light.ab = ab;
|
2012-12-03 13:29:03 -08:00
|
|
|
world->force_update = EINA_TRUE;
|
2012-10-30 11:31:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ephysics_world_ambient_light_color_get(const EPhysics_World *world, int *ar, int *ag, int *ab)
|
|
|
|
{
|
|
|
|
if (!world)
|
2012-10-10 13:32:08 -07:00
|
|
|
{
|
2012-10-30 11:31:32 -07:00
|
|
|
ERR("No world, can't get light properties.");
|
|
|
|
return;
|
2012-10-10 13:32:08 -07:00
|
|
|
}
|
|
|
|
|
2012-10-30 11:31:32 -07:00
|
|
|
if (ar) *ar = world->light.ar;
|
|
|
|
if (ag) *ag = world->light.ag;
|
|
|
|
if (ab) *ab = world->light.ab;
|
2012-10-10 13:32:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
2012-10-30 11:31:32 -07:00
|
|
|
ephysics_world_point_light_color_get(const EPhysics_World *world, int *lr, int *lg, int *lb)
|
2012-10-10 13:32:08 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
2012-10-30 11:31:32 -07:00
|
|
|
ERR("No world, can't get light properties.");
|
2012-10-10 13:32:08 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-30 11:31:32 -07:00
|
|
|
if (lr) *lr = world->light.lr;
|
|
|
|
if (lg) *lg = world->light.lg;
|
|
|
|
if (lb) *lb = world->light.lb;
|
2012-10-10 13:32:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
2012-10-30 11:31:32 -07:00
|
|
|
ephysics_world_point_light_position_get(const EPhysics_World *world, Evas_Coord *lx, Evas_Coord *ly, Evas_Coord *lz)
|
2012-10-10 13:32:08 -07:00
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
2012-10-30 11:31:32 -07:00
|
|
|
ERR("No world, can't get light properties.");
|
2012-10-10 13:32:08 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-30 11:31:32 -07:00
|
|
|
if (lx) *lx = world->light.lx;
|
|
|
|
if (ly) *ly = world->light.ly;
|
|
|
|
if (lz) *lz = world->light.lz;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ephysics_world_light_all_bodies_set(EPhysics_World *world, Eina_Bool enable)
|
|
|
|
{
|
|
|
|
if (!world)
|
2012-10-10 13:32:08 -07:00
|
|
|
{
|
2012-10-30 11:31:32 -07:00
|
|
|
ERR("No world, can't set light property.");
|
2012-10-10 13:32:08 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-30 11:31:32 -07:00
|
|
|
world->light.all_bodies = !!enable;
|
2012-12-03 13:29:03 -08:00
|
|
|
world->force_update = EINA_TRUE;
|
2012-10-10 13:32:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
ephysics_world_light_all_bodies_get(const EPhysics_World *world)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("No world, can't get light property.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
2012-10-30 11:31:32 -07:00
|
|
|
return world->light.all_bodies;
|
2012-10-10 13:32:08 -07:00
|
|
|
}
|
|
|
|
|
2012-10-25 14:55:23 -07:00
|
|
|
EAPI void
|
|
|
|
ephysics_world_stack_enable_set(EPhysics_World *world, Eina_Bool enabled)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("Can't enable / disable stacking, world wasn't provided.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
world->stacking = !!enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
ephysics_world_stack_enable_get(const EPhysics_World *world)
|
|
|
|
{
|
|
|
|
if (!world)
|
|
|
|
{
|
|
|
|
ERR("No world, no stacking status for you.");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return world->stacking;
|
|
|
|
}
|
|
|
|
|
2012-06-26 15:36:12 -07:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|