diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pointcache.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/rigidbody.c | 320 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/scene.c | 3 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 20 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 5 | ||||
-rw-r--r-- | source/blender/editors/include/ED_physics.h | 4 | ||||
-rw-r--r-- | source/blender/editors/object/object_add.c | 2 | ||||
-rw-r--r-- | source/blender/editors/physics/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/physics/physics_intern.h | 5 | ||||
-rw-r--r-- | source/blender/editors/physics/physics_ops.c | 4 | ||||
-rw-r--r-- | source/blender/editors/physics/rigidbody_constraint.c | 230 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_object_types.h | 1 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_rigidbody_types.h | 88 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_enum_types.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_object.c | 5 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_rigidbody.c | 289 |
17 files changed, 977 insertions, 7 deletions
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index cf1b21e91de..0c1a23bf41d 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -388,6 +388,7 @@ void BKE_object_free(Object *ob) free_partdeflect(ob->pd); BKE_rigidbody_free_object(ob); + BKE_rigidbody_free_constraint(ob); if (ob->soft) sbFree(ob->soft); if (ob->bsoft) bsbFree(ob->bsoft); @@ -1288,9 +1289,10 @@ static Object *object_copy_do(Object *ob, int copy_caches) } obn->soft = copy_softbody(ob->soft, copy_caches); obn->bsoft = copy_bulletsoftbody(ob->bsoft); + obn->rigidbody_object = BKE_rigidbody_copy_object(ob); + obn->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob); BKE_object_copy_particlesystems(obn, ob); - obn->rigidbody_object = BKE_rigidbody_copy_object(ob); obn->derivedDeform = NULL; obn->derivedFinal = NULL; diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index afc552ae7f3..1670389566e 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -2777,7 +2777,7 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode) } } - if (scene->rigidbody_world && ob->rigidbody_object) { + if (scene->rigidbody_world && (ob->rigidbody_object || ob->rigidbody_constraint)) { if (ob->rigidbody_object) ob->rigidbody_object->flag |= RBO_FLAG_NEEDS_RESHAPE; BKE_ptcache_id_from_rigidbody(&pid, ob, scene->rigidbody_world); diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 359c46f2b0e..d4a7013fb8f 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -74,13 +74,23 @@ /* Free rigidbody world */ void BKE_rigidbody_free_world(RigidBodyWorld *rbw) { - GroupObject *go; /* sanity check */ if (!rbw) return; if (rbw->physics_world) { /* free physics references, we assume that all physics objects in will have been added to the world */ + GroupObject *go; + if (rbw->constraints) { + for (go = rbw->constraints->gobject.first; go; go = go->next) { + if (go->ob && go->ob->rigidbody_constraint) { + RigidBodyCon *rbc = go->ob->rigidbody_constraint; + + if (rbc->physics_constraint) + RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); + } + } + } if (rbw->group) { for (go = rbw->group->gobject.first; go; go = go->next) { if (go->ob && go->ob->rigidbody_object) { @@ -134,6 +144,26 @@ void BKE_rigidbody_free_object(Object *ob) ob->rigidbody_object = NULL; } +/* Free RigidBody constraint and sim instance */ +void BKE_rigidbody_free_constraint(Object *ob) +{ + RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL; + + /* sanity check */ + if (rbc == NULL) + return; + + /* free physics reference */ + if (rbc->physics_constraint) { + RB_constraint_delete(rbc->physics_constraint); + rbc->physics_constraint = NULL; + } + + /* free data itself */ + MEM_freeN(rbc); + ob->rigidbody_constraint = NULL; +} + /* Copying Methods --------------------- */ /* These just copy the data, clearing out references to physics objects. @@ -161,6 +191,27 @@ RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) return rboN; } +RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) +{ + RigidBodyCon *rbcN = NULL; + + if (ob->rigidbody_constraint) { + /* just duplicate the whole struct first (to catch all the settings) */ + rbcN = MEM_dupallocN(ob->rigidbody_constraint); + + // RB_TODO be more clever about copying constrained objects + + /* tag object as needing to be verified */ + rbcN->flag |= RBC_FLAG_NEEDS_VALIDATE; + + /* clear out all the fields which need to be revalidated later */ + rbcN->physics_constraint = NULL; + } + + /* return new copy of settings */ + return rbcN; +} + /* ************************************** */ /* Setup Utilities - Validate Sim Instances */ @@ -381,6 +432,7 @@ void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short re return; /* make sure collision shape exists */ + /* FIXME we shouldn't always have to rebuild collision shapes when rebuilding objects, but it's needed for constraints to update correctly */ if (rbo->physics_shape == NULL || rebuild) BKE_rigidbody_validate_sim_shape(ob, true); @@ -428,6 +480,151 @@ void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short re /* --------------------- */ +/* Create physics sim representation of constraint given rigid body constraint settings + * < rebuild: even if an instance already exists, replace it + */ +void BKE_rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, short rebuild) +{ + RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL; + float loc[3]; + float rot[4]; + float lin_lower; + float lin_upper; + float ang_lower; + float ang_upper; + + /* sanity checks: + * - object should have a rigid body constraint + * - rigid body constraint should have at least one constrained object + */ + if (rbc == NULL) { + return; + } + + if (ELEM4(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) { + if (rbc->physics_constraint) { + RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); + RB_constraint_delete(rbc->physics_constraint); + rbc->physics_constraint = NULL; + } + return; + } + + if (rbc->physics_constraint) { + if (rebuild == false) + RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); + } + if (rbc->physics_constraint == NULL || rebuild) { + rbRigidBody *rb1 = rbc->ob1->rigidbody_object->physics_object; + rbRigidBody *rb2 = rbc->ob2->rigidbody_object->physics_object; + + /* remove constraint if it already exists before creating a new one */ + if (rbc->physics_constraint) { + RB_constraint_delete(rbc->physics_constraint); + rbc->physics_constraint = NULL; + } + + mat4_to_loc_quat(loc, rot, ob->obmat); + + if (rb1 && rb2) { + switch (rbc->type) { + case RBC_TYPE_POINT: + rbc->physics_constraint = RB_constraint_new_point(loc, rb1, rb2); + break; + case RBC_TYPE_FIXED: + rbc->physics_constraint = RB_constraint_new_fixed(loc, rot, rb1, rb2); + break; + case RBC_TYPE_HINGE: + rbc->physics_constraint = RB_constraint_new_hinge(loc, rot, rb1, rb2); + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) { + RB_constraint_set_limits_hinge(rbc->physics_constraint, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper); + } + else + RB_constraint_set_limits_hinge(rbc->physics_constraint, 0.0f, -1.0f); + break; + case RBC_TYPE_SLIDER: + rbc->physics_constraint = RB_constraint_new_slider(loc, rot, rb1, rb2); + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) + RB_constraint_set_limits_slider(rbc->physics_constraint, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper); + else + RB_constraint_set_limits_slider(rbc->physics_constraint, 0.0f, -1.0f); + break; + case RBC_TYPE_PISTON: + rbc->physics_constraint = RB_constraint_new_piston(loc, rot, rb1, rb2); + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) { + lin_lower = rbc->limit_lin_x_lower; + lin_upper = rbc->limit_lin_x_upper; + } + else { + lin_lower = 0.0f; + lin_upper = -1.0f; + } + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) { + ang_lower = rbc->limit_ang_x_lower; + ang_upper = rbc->limit_ang_x_upper; + } + else { + ang_lower = 0.0f; + ang_upper = -1.0f; + } + RB_constraint_set_limits_piston(rbc->physics_constraint, lin_lower, lin_upper, ang_lower, ang_upper); + break; + case RBC_TYPE_6DOF: + rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper); + else + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y) + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper); + else + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z) + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper); + else + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper); + else + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y) + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper); + else + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper); + else + RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f); + break; + } + } + + RB_constraint_set_enabled(rbc->physics_constraint, rbc->flag & RBC_FLAG_ENABLED); + + if (rbc->flag & RBC_FLAG_USE_BREAKING) + RB_constraint_set_breaking_threshold(rbc->physics_constraint, rbc->breaking_threshold); + else + RB_constraint_set_breaking_threshold(rbc->physics_constraint, FLT_MAX); + + if (rbc->flag & RBC_FLAG_OVERRIDE_SOLVER_ITERATIONS) + RB_constraint_set_solver_iterations(rbc->physics_constraint, rbc->num_solver_iterations); + else + RB_constraint_set_solver_iterations(rbc->physics_constraint, -1); + } + + if (rbw && rbw->physics_world && rbc->physics_constraint) { + RB_dworld_add_constraint(rbw->physics_world, rbc->physics_constraint, rbc->flag & RBC_FLAG_DISABLE_COLLISIONS); + } +} + +/* --------------------- */ + /* Create physics sim world given RigidBody world settings */ // NOTE: this does NOT update object references that the scene uses, in case those aren't ready yet! void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, short rebuild) @@ -536,6 +733,55 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) return rbo; } +/* Add rigid body constraint to the specified object */ +RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type) +{ + RigidBodyCon *rbc; + RigidBodyWorld *rbw = scene->rigidbody_world; + + /* sanity checks + * - rigidbody world must exist + * - object must exist + * - cannot add constraint if it already exists + */ + if (ob == NULL || (ob->rigidbody_constraint != NULL)) + return NULL; + + /* create new settings data, and link it up */ + rbc = MEM_callocN(sizeof(RigidBodyCon), "RigidBodyCon"); + + /* set default settings */ + rbc->type = type; + + rbc->ob1 = NULL; + rbc->ob2 = NULL; + + rbc->flag |= RBC_FLAG_ENABLED; + rbc->flag |= RBC_FLAG_DISABLE_COLLISIONS; + + rbc->breaking_threshold = 10.0f; /* no good default here, just use 10 for now */ + rbc->num_solver_iterations = 10; /* 10 is Bullet default */ + + rbc->limit_lin_x_lower = -1.0f; + rbc->limit_lin_x_upper = 1.0f; + rbc->limit_lin_y_lower = -1.0f; + rbc->limit_lin_y_upper = 1.0f; + rbc->limit_lin_z_lower = -1.0f; + rbc->limit_lin_z_upper = 1.0f; + rbc->limit_ang_x_lower = -M_PI_4; + rbc->limit_ang_x_upper = M_PI_4; + rbc->limit_ang_y_lower = -M_PI_4; + rbc->limit_ang_y_upper = M_PI_4; + rbc->limit_ang_z_lower = -M_PI_4; + rbc->limit_ang_z_upper = M_PI_4; + + /* flag cache as outdated */ + BKE_rigidbody_cache_reset(rbw); + + /* return this object */ + return rbc; +} + /* ************************************** */ /* Utilities API */ @@ -555,6 +801,7 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob) { RigidBodyWorld *rbw = scene->rigidbody_world; RigidBodyOb *rbo = ob->rigidbody_object; + RigidBodyCon *rbc; GroupObject *go; int i; @@ -572,9 +819,46 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob) } } } + + /* remove object from rigid body constraints */ + if (rbw->constraints) { + for (go = rbw->constraints->gobject.first; go; go = go->next) { + Object *obt = go->ob; + if (obt) { + rbc = obt->rigidbody_constraint; + if (rbc->ob1 == ob) { + rbc->ob1 = NULL; + rbc->flag |= RBC_FLAG_NEEDS_VALIDATE; + } + if (rbc->ob2 == ob) { + rbc->ob2 = NULL; + rbc->flag |= RBC_FLAG_NEEDS_VALIDATE; + } + } + } + } } + /* remove object's settings */ BKE_rigidbody_free_object(ob); + + /* flag cache as outdated */ + BKE_rigidbody_cache_reset(rbw); +} + +void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) +{ + RigidBodyWorld *rbw = scene->rigidbody_world; + RigidBodyCon *rbc = ob->rigidbody_constraint; + + if (rbw) { + /* remove from rigidbody world, free object won't do this */ + if (rbw && rbw->physics_world && rbc->physics_constraint) + RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); + } + /* remove object's settings */ + BKE_rigidbody_free_constraint(ob); + /* flag cache as outdated */ BKE_rigidbody_cache_reset(rbw); } @@ -746,6 +1030,40 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r rigidbody_update_sim_ob(scene, rbw, ob, rbo); } } + /* update constraints */ + if (rbw->constraints == NULL) /* no constraints, move on */ + return; + for (go = rbw->constraints->gobject.first; go; go = go->next) { + Object *ob = go->ob; + + if (ob) { + /* validate that we've got valid object set up here... */ + RigidBodyCon *rbc = ob->rigidbody_constraint; + /* update transformation matrix of the object so we don't get a frame of lag for simple animations */ + BKE_object_where_is_calc(scene, ob); + + if (rbc == NULL) { + /* Since this object is included in the group but doesn't have + * constraint settings (perhaps it was added manually), add! + */ + ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED); + BKE_rigidbody_validate_sim_constraint(rbw, ob, true); + + rbc = ob->rigidbody_constraint; + } + else { + /* perform simulation data updates as tagged */ + if (rebuild) { + /* World has been rebuilt so rebuild constraint */ + BKE_rigidbody_validate_sim_constraint(rbw, ob, true); + } + else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) { + BKE_rigidbody_validate_sim_constraint(rbw, ob, false); + } + rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE; + } + } + } } /* Sync rigid body and object transformations */ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index b0938f78435..fa3dac67a7f 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -943,6 +943,9 @@ Base *BKE_scene_base_add(Scene *sce, Object *ob) void BKE_scene_base_remove(Scene *sce, Base *base) { + /* remove rigid body constraint from world before removing object */ + if (base->object->rigidbody_constraint) + BKE_rigidbody_remove_constraint(sce, base->object); /* remove rigid body object from world before removing object */ if (base->object->rigidbody_object) BKE_rigidbody_remove_object(sce, base->object); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index edb033e80f8..070cb4676a1 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4363,6 +4363,11 @@ static void lib_link_object(FileData *fd, Main *main) lib_link_particlesystems(fd, ob, &ob->id, &ob->particlesystem); lib_link_modifiers(fd, ob); + + if (ob->rigidbody_constraint) { + ob->rigidbody_constraint->ob1 = newlibadr(fd, ob->id.lib, ob->rigidbody_constraint->ob1); + ob->rigidbody_constraint->ob2 = newlibadr(fd, ob->id.lib, ob->rigidbody_constraint->ob2); + } } } @@ -4797,7 +4802,10 @@ static void direct_link_object(FileData *fd, Object *ob) rbo->physics_object = NULL; rbo->physics_shape = NULL; } - + ob->rigidbody_constraint = newdataadr(fd, ob->rigidbody_constraint); + if (ob->rigidbody_constraint) + ob->rigidbody_constraint->physics_constraint = NULL; + link_list(fd, &ob->particlesystem); direct_link_particlesystems(fd, &ob->particlesystem); @@ -5021,6 +5029,8 @@ static void lib_link_scene(FileData *fd, Main *main) RigidBodyWorld *rbw = sce->rigidbody_world; if (rbw->group) rbw->group = newlibadr(fd, sce->id.lib, rbw->group); + if (rbw->constraints) + rbw->constraints = newlibadr(fd, sce->id.lib, rbw->constraints); if (rbw->effector_weights) rbw->effector_weights->group = newlibadr(fd, sce->id.lib, rbw->effector_weights->group); } @@ -9679,7 +9689,12 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob) if (ob->pd && ob->pd->tex) expand_doit(fd, mainvar, ob->pd->tex); - + + if (ob->rigidbody_constraint) { + expand_doit(fd, mainvar, ob->rigidbody_constraint->ob1); + expand_doit(fd, mainvar, ob->rigidbody_constraint->ob2); + } + } static void expand_scene(FileData *fd, Main *mainvar, Scene *sce) @@ -9728,6 +9743,7 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce) if (sce->rigidbody_world) { expand_doit(fd, mainvar, sce->rigidbody_world->group); + expand_doit(fd, mainvar, sce->rigidbody_world->constraints); } #ifdef DURIAN_CAMERA_SWITCH diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ebd752c0118..e7a53670849 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1492,7 +1492,10 @@ static void write_objects(WriteData *wd, ListBase *idbase) // TODO: if any extra data is added to handle duplis, will need separate function then writestruct(wd, DATA, "RigidBodyOb", 1, ob->rigidbody_object); } - + if (ob->rigidbody_constraint) { + writestruct(wd, DATA, "RigidBodyCon", 1, ob->rigidbody_constraint); + } + write_particlesystems(wd, &ob->particlesystem); write_modifiers(wd, &ob->modifiers); } diff --git a/source/blender/editors/include/ED_physics.h b/source/blender/editors/include/ED_physics.h index d5aee5bbb9e..192bcd8f712 100644 --- a/source/blender/editors/include/ED_physics.h +++ b/source/blender/editors/include/ED_physics.h @@ -48,6 +48,10 @@ int PE_poll_view3d(struct bContext *C); void ED_rigidbody_ob_add(struct wmOperator *op, struct Scene *scene, struct Object *ob, int type); void ED_rigidbody_ob_remove(struct Scene *scene, struct Object *ob); +/* rigidbody_constraint.c */ +void ED_rigidbody_con_add(struct wmOperator *op, struct Scene *scene, struct Object *ob, int type); +void ED_rigidbody_con_remove(struct Scene *scene, struct Object *ob); + /* operators */ void ED_operatortypes_physics(void); void ED_keymap_physics(struct wmKeyConfig *keyconf); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index b7ac93c5996..9c829a06cd2 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1701,7 +1701,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base * 2) Rigid Body sim participants MUST always be part of a group... */ // XXX: is 2) really a good measure here? - if ((basen->flag & OB_FROMGROUP) || ob->rigidbody_object) { + if ((basen->flag & OB_FROMGROUP) || ob->rigidbody_object || ob->rigidbody_constraint) { Group *group; for (group = bmain->group.first; group; group = group->id.next) { if (object_in_group(ob, group)) diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt index f14882884c0..7f3eaa892d0 100644 --- a/source/blender/editors/physics/CMakeLists.txt +++ b/source/blender/editors/physics/CMakeLists.txt @@ -44,6 +44,7 @@ set(SRC physics_fluid.c physics_ops.c physics_pointcache.c + rigidbody_constraint.c rigidbody_object.c rigidbody_world.c diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h index b4b4b5e54f5..4b4855c9922 100644 --- a/source/blender/editors/physics/physics_intern.h +++ b/source/blender/editors/physics/physics_intern.h @@ -115,6 +115,11 @@ void RIGIDBODY_OT_objects_remove(struct wmOperatorType *ot); void RIGIDBODY_OT_shape_change(struct wmOperatorType *ot); void RIGIDBODY_OT_mass_calculate(struct wmOperatorType *ot); +/* rigidbody_constraint.c */ +void RIGIDBODY_OT_constraint_add(struct wmOperatorType *ot); +void RIGIDBODY_OT_constraint_group_add(struct wmOperatorType *ot); +void RIGIDBODY_OT_constraint_remove(struct wmOperatorType *ot); + /*rigidbody_world.c */ void RIGIDBODY_OT_world_add(struct wmOperatorType *ot); void RIGIDBODY_OT_world_remove(struct wmOperatorType *ot); diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c index 7a893ab47a4..fc6a0e58752 100644 --- a/source/blender/editors/physics/physics_ops.c +++ b/source/blender/editors/physics/physics_ops.c @@ -96,6 +96,10 @@ static void operatortypes_particle(void) WM_operatortype_append(RIGIDBODY_OT_shape_change); WM_operatortype_append(RIGIDBODY_OT_mass_calculate); + WM_operatortype_append(RIGIDBODY_OT_constraint_add); + WM_operatortype_append(RIGIDBODY_OT_constraint_group_add); + WM_operatortype_append(RIGIDBODY_OT_constraint_remove); + WM_operatortype_append(RIGIDBODY_OT_world_add); WM_operatortype_append(RIGIDBODY_OT_world_remove); // WM_operatortype_append(RIGIDBODY_OT_world_export); diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c new file mode 100644 index 00000000000..e4db1c91c2b --- /dev/null +++ b/source/blender/editors/physics/rigidbody_constraint.c @@ -0,0 +1,230 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Sergej Reich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file rigidbody_constraint.c + * \ingroup editor_physics + * \brief Rigid Body constraint editing operators + */ + +#include <stdlib.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_group_types.h" +#include "DNA_object_types.h" +#include "DNA_rigidbody_types.h" +#include "DNA_scene_types.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" + +#include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_group.h" +#include "BKE_object.h" +#include "BKE_report.h" +#include "BKE_rigidbody.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_physics.h" +#include "ED_screen.h" + +#include "physics_intern.h" + +/* ********************************************** */ +/* Helper API's for RigidBody Constraint Editing */ + +static int ED_operator_rigidbody_con_active_poll(bContext *C) +{ + if (ED_operator_object_active_editable(C)) { + Object *ob = CTX_data_active_object(C); + return (ob && ob->rigidbody_constraint); + } + else + return 0; +} + + +void ED_rigidbody_con_add(wmOperator *op, Scene *scene, Object *ob, int type) +{ + /* check that object doesn't already have a constraint */ + if (ob->rigidbody_constraint) { + BKE_reportf(op->reports, RPT_INFO, "Object '%s' already has a Rigid Body Constraint", ob->id.name + 2); + return; + } + + /* make rigidbody constraint settings */ + ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, type); + ob->rigidbody_constraint->flag |= RBC_FLAG_NEEDS_VALIDATE; +} + +void ED_rigidbody_con_remove(Scene *scene, Object *ob) +{ + BKE_rigidbody_remove_constraint(scene, ob); + DAG_id_tag_update(&ob->id, OB_RECALC_OB); +} + +/* ********************************************** */ +/* Active Object Add/Remove Operators */ + +/* ************ Add Rigid Body Constraint ************** */ + +static int rigidbody_con_add_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = (scene) ? OBACT : NULL; + int type = RNA_enum_get(op->ptr, "type"); + + /* apply to active object */ + ED_rigidbody_con_add(op, scene, ob, type); + + /* send updates */ + DAG_ids_flush_update(CTX_data_main(C), 0); + + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + + /* done */ + return OPERATOR_FINISHED; +} + +void RIGIDBODY_OT_constraint_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->idname = "RIGIDBODY_OT_constraint_add"; + ot->name = "Add Rigid Body Constraint"; + ot->description = "Add Rigid Body Constraint to active object"; + + /* callbacks */ + ot->exec = rigidbody_con_add_exec; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", rigidbody_con_type_items, RBC_TYPE_FIXED, "Rigid Body Constraint Type", ""); +} + +static int rigidbody_con_group_add_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene); + Object *ob = (scene) ? OBACT : NULL; + int type = RNA_enum_get(op->ptr, "type"); + + /* sanity checks */ + if (ELEM(NULL, scene, rbw)) { + BKE_report(op->reports, RPT_ERROR, "No Rigid Body World to add Rigid Body Constraint to"); + return OPERATOR_CANCELLED; + } + if (rbw->constraints == NULL) { + rbw->constraints = add_group("RigidBodyConstraints"); + } + /* apply to active object */ + ED_rigidbody_con_add(op, scene, ob, type); + add_to_group(rbw->constraints, ob, scene, NULL); + + /* send updates */ + DAG_ids_flush_update(CTX_data_main(C), 0); + + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + + /* done */ + return OPERATOR_FINISHED; +} + +void RIGIDBODY_OT_constraint_group_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->idname = "RIGIDBODY_OT_constraint_group_add"; + ot->name = "Add Rigid Body Constraint"; + ot->description = "Add Rigid Body Constraint to active object and world's group"; + + /* callbacks */ + ot->exec = rigidbody_con_group_add_exec; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", rigidbody_con_type_items, RBC_TYPE_FIXED, "Rigid Body Constraint Type", ""); +} + +/* ************ Remove Rigid Body Constraint ************** */ + +static int rigidbody_con_remove_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = (scene) ? OBACT : NULL; + + /* sanity checks */ + if (scene == NULL) + return OPERATOR_CANCELLED; + + /* apply to active object */ + if (ELEM(NULL, ob, ob->rigidbody_constraint)) { + BKE_report(op->reports, RPT_ERROR, "Object has no Rigid Body Constraint to remove"); + return OPERATOR_CANCELLED; + } + else { + ED_rigidbody_con_remove(scene, ob); + } + + /* send updates */ + DAG_ids_flush_update(CTX_data_main(C), 0); + + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL); + + /* done */ + return OPERATOR_FINISHED; +} + +void RIGIDBODY_OT_constraint_remove(wmOperatorType *ot) +{ + /* identifiers */ + ot->idname = "RIGIDBODY_OT_constraint_remove"; + ot->name = "Remove Rigid Body Constraint"; + ot->description = "Remove Rigid Body Constraint from Object"; + + /* callbacks */ + ot->exec = rigidbody_con_remove_exec; + ot->poll = ED_operator_rigidbody_con_active_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 16859e5975a..a1bb9fb9c3d 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -273,6 +273,7 @@ typedef struct Object { ListBase *duplilist; /* for temporary dupli list storage, only for use by RNA API */ struct RigidBodyOb *rigidbody_object; /* settings for Bullet rigid body */ + struct RigidBodyCon *rigidbody_constraint; /* settings for Bullet constraint */ float ima_ofs[2]; /* offset for image empties */ } Object; diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h index e08162fedd6..5b7ffe4209c 100644 --- a/source/blender/makesdna/DNA_rigidbody_types.h +++ b/source/blender/makesdna/DNA_rigidbody_types.h @@ -53,6 +53,8 @@ typedef struct RigidBodyWorld { struct Group *group; /* Group containing objects to use for Rigid Bodies */ struct Object **objects; /* Array to access group objects by index, only used at runtime */ + struct Group *constraints; /* Group containing objects to use for Rigid Body Constraints*/ + int pad; float ltime; /* last frame world was evaluated for (internal) */ @@ -172,6 +174,92 @@ typedef enum eRigidBody_Shape { } eRigidBody_Shape; /* ******************************** */ +/* RigidBody Constraint */ + +/* RigidBodyConstraint (rbc) + * + * Represents an constraint connecting two rigid bodies. + */ +typedef struct RigidBodyCon { + struct Object *ob1; /* First object influenced by the constraint */ + struct Object *ob2; /* Second object influenced by the constraint */ + + /* General Settings for this RigidBodyCon */ + short type; /* (eRigidBodyCon_Type) role of RigidBody in sim */ + short num_solver_iterations;/* number of constraint solver iterations made per simulation step */ + + int flag; /* (eRigidBodyCon_Flag) */ + + float breaking_threshold; /* breaking impulse threshold */ + float pad; + + /* limits */ + float limit_lin_x_lower; /* lower limit for x axis translation */ + float limit_lin_x_upper; /* upper limit for x axis translation */ + float limit_lin_y_lower; /* lower limit for y axis translation */ + float limit_lin_y_upper; /* upper limit for y axis translation */ + float limit_lin_z_lower; /* lower limit for z axis translation */ + float limit_lin_z_upper; /* upper limit for z axis translation */ + float limit_ang_x_lower; /* lower limit for x axis rotation */ + float limit_ang_x_upper; /* upper limit for x axis rotation */ + float limit_ang_y_lower; /* lower limit for y axis rotation */ + float limit_ang_y_upper; /* upper limit for y axis rotation */ + float limit_ang_z_lower; /* lower limit for z axis rotation */ + float limit_ang_z_upper; /* upper limit for z axis rotation */ + + /* References to Physics Sim object. Exist at runtime only */ + void *physics_constraint; /* Physics object representation (i.e. btTypedConstraint) */ +} RigidBodyCon; + + +/* Participation types for RigidBodyOb */ +typedef enum eRigidBodyCon_Type { + /* lets bodies rotate around a specified point */ + RBC_TYPE_POINT = 0, + /* lets bodies rotate around a specified axis */ + RBC_TYPE_HINGE, + /* simulates wheel suspension */ + RBC_TYPE_HINGE2, + /* restricts movent to a specified axis */ + RBC_TYPE_SLIDER, + /* lets object rotate within a cpecified cone */ + RBC_TYPE_CONE_TWIST, + /* allows user to specify constraint axes */ + RBC_TYPE_6DOF, + /* like 6DOF but has springs */ + RBC_TYPE_6DOF_SPRING, + /* simulates a universal joint */ + RBC_TYPE_UNIVERSAL, + /* glues two bodies together */ + RBC_TYPE_FIXED, + /* similar to slider but also allows rotation around slider axis */ + RBC_TYPE_PISTON, + /* Simplified spring constraint with only once axis that's automatically placed between the connected bodies */ + RBC_TYPE_SPRING +} eRigidBodyCon_Type; + +/* Flags for RigidBodyCon */ +typedef enum eRigidBodyCon_Flag { + /* constraint influences rigid body motion */ + RBC_FLAG_ENABLED = (1<<0), + /* constraint needs to be validated */ + RBC_FLAG_NEEDS_VALIDATE = (1<<1), + /* allow constrained bodies to collide */ + RBC_FLAG_DISABLE_COLLISIONS = (1<<2), + /* constraint can break */ + RBC_FLAG_USE_BREAKING = (1<<3), + /* constraint use custom number of constraint solver iterations */ + RBC_FLAG_OVERRIDE_SOLVER_ITERATIONS = (1<<4), + /* limits */ + RBC_FLAG_USE_LIMIT_LIN_X = (1<<5), + RBC_FLAG_USE_LIMIT_LIN_Y = (1<<6), + RBC_FLAG_USE_LIMIT_LIN_Z = (1<<7), + RBC_FLAG_USE_LIMIT_ANG_X = (1<<8), + RBC_FLAG_USE_LIMIT_ANG_Y = (1<<9), + RBC_FLAG_USE_LIMIT_ANG_Z = (1<<10), +} eRigidBodyCon_Flag; + +/* ******************************** */ #endif /* __DNA_RIGIDBODY_TYPES_H__ */ diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index f0de36bbdfe..eabf0391c01 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -104,6 +104,7 @@ extern EnumPropertyItem object_type_curve_items[]; extern EnumPropertyItem rigidbody_ob_type_items[]; extern EnumPropertyItem rigidbody_ob_shape_items[]; +extern EnumPropertyItem rigidbody_con_type_items[]; extern EnumPropertyItem object_axis_items[]; diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 99cecb01140..47b775801f6 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2433,6 +2433,11 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "rigidbody_object"); RNA_def_property_struct_type(prop, "RigidBodyObject"); RNA_def_property_ui_text(prop, "Rigid Body Settings", "Settings for rigid body simulation"); + + prop = RNA_def_property(srna, "rigid_body_constraint", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "rigidbody_constraint"); + RNA_def_property_struct_type(prop, "RigidBodyConstraint"); + RNA_def_property_ui_text(prop, "Rigid Body Constraint", "Constraint constraining rigid bodies"); /* restrict */ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index 1e0e250ac66..206c6e19c41 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -59,6 +59,16 @@ EnumPropertyItem rigidbody_ob_shape_items[] = { {RB_SHAPE_TRIMESH, "MESH", ICON_MESH_MONKEY, "Mesh", "Mesh consisting of triangles only, allowing for more detailed interactions than convex hulls"}, {0, NULL, 0, NULL, NULL}}; +/* collision shapes of constraints in rigid body sim */ +EnumPropertyItem rigidbody_con_type_items[] = { + {RBC_TYPE_FIXED, "FIXED", ICON_FORCE_FORCE, "Fixed", "Glues rigid bodies together"}, + {RBC_TYPE_POINT, "POINT", ICON_FORCE_FORCE, "Point", "Constrains rigid bodies to move aound common pivot point"}, + {RBC_TYPE_HINGE, "HINGE", ICON_FORCE_FORCE, "Hinge", "Restricts rigid body rotation to one axis"}, + {RBC_TYPE_SLIDER, "SLIDER", ICON_FORCE_FORCE, "Slider", "Restricts rigid boddy translation to one axis"}, + {RBC_TYPE_PISTON, "PISTON", ICON_FORCE_FORCE, "Piston", "Restricts rigid boddy translation and rotation to one axis"}, + {RBC_TYPE_6DOF, "GENERIC", ICON_FORCE_FORCE, "Generic", "Restricts translation and rotation to specified axes"}, + {0, NULL, 0, NULL, NULL}}; + #ifdef RNA_RUNTIME @@ -286,6 +296,91 @@ static void rna_RigidBodyOb_angular_damping_set(PointerRNA *ptr, float value) RB_body_set_angular_damping(rbo->physics_object, value); } +static char *rna_RigidBodyCon_path(PointerRNA *ptr) +{ + /* NOTE: this hardcoded path should work as long as only Objects have this */ + return BLI_sprintfN("rigid_body_constraint"); +} + +static void rna_RigidBodyCon_type_set(PointerRNA *ptr, int value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->type = value; + rbc->flag |= RBC_FLAG_NEEDS_VALIDATE; +} + +static void rna_RigidBodyCon_enabled_set(PointerRNA *ptr, int value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + RB_FLAG_SET(rbc->flag, value, RBC_FLAG_ENABLED); + + if (rbc->physics_constraint) + RB_constraint_set_enabled(rbc->physics_constraint, value); +} + +static void rna_RigidBodyCon_disable_collisions_set(PointerRNA *ptr, int value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + RB_FLAG_SET(rbc->flag, value, RBC_FLAG_DISABLE_COLLISIONS); + + rbc->flag |= RBC_FLAG_NEEDS_VALIDATE; +} + +static void rna_RigidBodyCon_use_breaking_set(PointerRNA *ptr, int value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + if (value) { + rbc->flag |= RBC_FLAG_USE_BREAKING; + if (rbc->physics_constraint) + RB_constraint_set_breaking_threshold(rbc->physics_constraint, rbc->breaking_threshold); + } + else { + rbc->flag &= ~RBC_FLAG_USE_BREAKING; + if (rbc->physics_constraint) + RB_constraint_set_breaking_threshold(rbc->physics_constraint, FLT_MAX); + } +} + +static void rna_RigidBodyCon_breaking_threshold_set(PointerRNA *ptr, float value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->breaking_threshold = value; + + if (rbc->physics_constraint && (rbc->flag & RBC_FLAG_USE_BREAKING)) + RB_constraint_set_breaking_threshold(rbc->physics_constraint, value); +} + +static void rna_RigidBodyCon_override_solver_iterations_set(PointerRNA *ptr, int value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + if (value) { + rbc->flag |= RBC_FLAG_OVERRIDE_SOLVER_ITERATIONS; + if (rbc->physics_constraint) + RB_constraint_set_solver_iterations(rbc->physics_constraint, rbc->num_solver_iterations); + } + else { + rbc->flag &= ~RBC_FLAG_OVERRIDE_SOLVER_ITERATIONS; + if (rbc->physics_constraint) + RB_constraint_set_solver_iterations(rbc->physics_constraint, -1); + } +} + +static void rna_RigidBodyCon_num_solver_iterations_set(PointerRNA *ptr, int value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->num_solver_iterations = value; + + if (rbc->physics_constraint && (rbc->flag & RBC_FLAG_OVERRIDE_SOLVER_ITERATIONS)) + RB_constraint_set_solver_iterations(rbc->physics_constraint, value); +} + #else static void rna_def_rigidbody_world(BlenderRNA *brna) @@ -304,6 +399,12 @@ static void rna_def_rigidbody_world(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_EDITABLE|PROP_ID_SELF_CHECK); RNA_def_property_ui_text(prop, "Group", "Group containing objects participating in this simulation"); RNA_def_property_update(prop, NC_SCENE, "rna_RigidBodyWorld_reset"); + + prop = RNA_def_property(srna, "constraints", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "Group"); + RNA_def_property_flag(prop, PROP_EDITABLE|PROP_ID_SELF_CHECK); + RNA_def_property_ui_text(prop, "Constraints", "Group containing rigid body constraint objects"); + RNA_def_property_update(prop, NC_SCENE, "rna_RigidBodyWorld_reset"); /* booleans */ prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE); @@ -501,10 +602,198 @@ static void rna_def_rigidbody_object(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); } +static void rna_def_rigidbody_constraint(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "RigidBodyConstraint", NULL); + RNA_def_struct_sdna(srna, "RigidBodyCon"); + RNA_def_struct_ui_text(srna, "Rigid Body Constraint", "Constraint influencing Objects inside Rigid Body Simulation"); + RNA_def_struct_path_func(srna, "rna_RigidBodyCon_path"); + + /* Enums */ + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, rigidbody_con_type_items); + RNA_def_property_enum_funcs(prop, NULL, "rna_RigidBodyCon_type_set", NULL); + RNA_def_property_ui_text(prop, "Type", "Type of Rigid Body Constraint"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_ENABLED); + RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyCon_enabled_set"); + RNA_def_property_ui_text(prop, "Enabled", "Enable this constraint"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "disable_collisions", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_DISABLE_COLLISIONS); + RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyCon_disable_collisions_set"); + RNA_def_property_ui_text(prop, "Disable Collisions", "Disables collisions between constrained ridid bodies"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "object1", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "ob1"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Object 1", "First Rigid Body Object to be constrained"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "object2", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "ob2"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Object 2", "Second Rigid Body Object to be constrained"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + /* Breaking Threshold */ + prop = RNA_def_property(srna, "use_breaking", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_BREAKING); + RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyCon_use_breaking_set"); + RNA_def_property_ui_text(prop, "Breakable", "Constraint can be broaken if it receives an impulse above the threshold"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "breaking_threshold", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "breaking_threshold"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 100.0, 2); + RNA_def_property_float_default(prop, 10.0f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_breaking_threshold_set", NULL); + RNA_def_property_ui_text(prop, "Breaking Threshold", "Impulse threshold that must be reached for the constraint to break"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + /* Solver Iterations */ + prop = RNA_def_property(srna, "override_solver_iterations", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_OVERRIDE_SOLVER_ITERATIONS); + RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyCon_override_solver_iterations_set"); + RNA_def_property_ui_text(prop, "Override Solver Iterations", "Overrides the number of solver iterations for this constraint"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "num_solver_iterations", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "num_solver_iterations"); + RNA_def_property_range(prop, 1, 1000); + RNA_def_property_ui_range(prop, 1, 100, 1, 0); + RNA_def_property_int_default(prop, 10); + RNA_def_property_int_funcs(prop, NULL, "rna_RigidBodyCon_num_solver_iterations_set", NULL); + RNA_def_property_ui_text(prop, "Solver Iterations", "Number of constraint solver iterations made per simulation step (higher values are more accurate but slower)"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + + /* Limits */ + prop = RNA_def_property(srna, "use_limit_lin_x", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_LIMIT_LIN_X); + RNA_def_property_ui_text(prop, "X Axis", "Limits translation on x axis"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "use_limit_lin_y", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_LIMIT_LIN_Y); + RNA_def_property_ui_text(prop, "Y Axis", "Limits translation on y axis"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "use_limit_lin_z", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_LIMIT_LIN_Z); + RNA_def_property_ui_text(prop, "Z Axis", "Limits translation on z axis"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "use_limit_ang_x", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_LIMIT_ANG_X); + RNA_def_property_ui_text(prop, "X Angle", "Limits rotation around x axis"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "use_limit_ang_y", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_LIMIT_ANG_Y); + RNA_def_property_ui_text(prop, "Y Angle", "Limits rotation around y axis"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "use_limit_ang_z", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_LIMIT_ANG_Z); + RNA_def_property_ui_text(prop, "Z Angle", "Limits rotation around z axis"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "limit_lin_x_lower", PROP_FLOAT, PROP_UNIT_LENGTH); + RNA_def_property_float_sdna(prop, NULL, "limit_lin_x_lower"); + RNA_def_property_float_default(prop, -1.0f); + RNA_def_property_ui_text(prop, "Lower X Limit", "Lower limit of x axis translation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "limit_lin_x_upper", PROP_FLOAT, PROP_UNIT_LENGTH); + RNA_def_property_float_sdna(prop, NULL, "limit_lin_x_upper"); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Upper X Limit", "Upper limit of x axis translation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "limit_lin_y_lower", PROP_FLOAT, PROP_UNIT_LENGTH); + RNA_def_property_float_sdna(prop, NULL, "limit_lin_y_lower"); + RNA_def_property_float_default(prop, -1.0f); + RNA_def_property_ui_text(prop, "Lower Y Limit", "Lower limit of y axis translation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "limit_lin_y_upper", PROP_FLOAT, PROP_UNIT_LENGTH); + RNA_def_property_float_sdna(prop, NULL, "limit_lin_y_upper"); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Upper Y Limit", "Upper limit of y axis translation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "limit_lin_z_lower", PROP_FLOAT, PROP_UNIT_LENGTH); + RNA_def_property_float_sdna(prop, NULL, "limit_lin_z_lower"); + RNA_def_property_float_default(prop, -1.0f); + RNA_def_property_ui_text(prop, "Lower Z Limit", "Lower limit of z axis translation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "limit_lin_z_upper", PROP_FLOAT, PROP_UNIT_LENGTH); + RNA_def_property_float_sdna(prop, NULL, "limit_lin_z_upper"); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Upper Z Limit", "Upper limit of z axis translation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "limit_ang_x_lower", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "limit_ang_x_lower"); + RNA_def_property_range(prop, -M_PI * 2, M_PI * 2); + RNA_def_property_float_default(prop, -M_PI_4); + RNA_def_property_ui_text(prop, "Lower X Angle Limit", "Lower limit of x axis rotation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "limit_ang_x_upper", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "limit_ang_x_upper"); + RNA_def_property_range(prop, -M_PI * 2, M_PI * 2); + RNA_def_property_float_default(prop, M_PI_4); + RNA_def_property_ui_text(prop, "Upper X Angle Limit", "Upper limit of x axis rotation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "limit_ang_y_lower", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "limit_ang_y_lower"); + RNA_def_property_range(prop, -M_PI * 2, M_PI * 2); + RNA_def_property_float_default(prop, -M_PI_4); + RNA_def_property_ui_text(prop, "Lower Y Angle Limit", "Lower limit of y axis rotation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "limit_ang_y_upper", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "limit_ang_y_upper"); + RNA_def_property_range(prop, -M_PI * 2, M_PI * 2); + RNA_def_property_float_default(prop, M_PI_4); + RNA_def_property_ui_text(prop, "Upper Y Angle Limit", "Upper limit of y axis rotation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "limit_ang_z_lower", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "limit_ang_z_lower"); + RNA_def_property_range(prop, -M_PI * 2, M_PI * 2); + RNA_def_property_float_default(prop, -M_PI_4); + RNA_def_property_ui_text(prop, "Lower Z Angle Limit", "Lower limit of z axis rotation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "limit_ang_z_upper", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "limit_ang_z_upper"); + RNA_def_property_range(prop, -M_PI * 2, M_PI * 2); + RNA_def_property_float_default(prop, M_PI_4); + RNA_def_property_ui_text(prop, "Upper Z Angle Limit", "Upper limit of z axis rotation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_RigidBodyOb_reset"); +} + void RNA_def_rigidbody(BlenderRNA *brna) { rna_def_rigidbody_world(brna); rna_def_rigidbody_object(brna); + rna_def_rigidbody_constraint(brna); } |