Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_operators/rigidbody.py60
-rw-r--r--release/scripts/startup/bl_ui/__init__.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_common.py5
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py215
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py2
-rw-r--r--source/blender/blenkernel/intern/object.c4
-rw-r--r--source/blender/blenkernel/intern/pointcache.c2
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c320
-rw-r--r--source/blender/blenkernel/intern/scene.c3
-rw-r--r--source/blender/blenloader/intern/readfile.c20
-rw-r--r--source/blender/blenloader/intern/writefile.c5
-rw-r--r--source/blender/editors/include/ED_physics.h4
-rw-r--r--source/blender/editors/object/object_add.c2
-rw-r--r--source/blender/editors/physics/CMakeLists.txt1
-rw-r--r--source/blender/editors/physics/physics_intern.h5
-rw-r--r--source/blender/editors/physics/physics_ops.c4
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c230
-rw-r--r--source/blender/makesdna/DNA_object_types.h1
-rw-r--r--source/blender/makesdna/DNA_rigidbody_types.h88
-rw-r--r--source/blender/makesrna/RNA_enum_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_object.c5
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c289
22 files changed, 1260 insertions, 7 deletions
diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py
index 55a2cef4535..5363eba6420 100644
--- a/release/scripts/startup/bl_operators/rigidbody.py
+++ b/release/scripts/startup/bl_operators/rigidbody.py
@@ -188,3 +188,63 @@ class BakeToKeyframes(Operator):
wm = context.window_manager
return wm.invoke_props_dialog(self)
+
+class ConnectRigidBodies(Operator):
+
+
+ '''Connect selected rigid bodies to active'''
+ bl_idname = "rigidbody.connect"
+ bl_label = "ConnectRigidBodies"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ con_type = EnumProperty(
+ name="Type",
+ description="Type of generated contraint",
+ items=(('FIXED', "Fixed", "Glues ridig bodies together"),
+ ('POINT', "Point", "Constrains rigid bodies to move aound common pivot point"),
+ ('HINGE', "Hinge", "Restricts rigid body rotation to one axis"),
+ ('SLIDER', "Slider", "Restricts rigid boddy translation to one axis"),
+ ('PISTON', "Piston", "Restricts rigid boddy translation and rotation to one axis"),
+ ('GENERIC', "Generic", "Restricts translation and rotation to specified axes"),
+ default='FIXED',)
+
+ pivot_type = EnumProperty(
+ name="Location",
+ description="Constraint pivot location",
+ items=(('CENTER', "Center", "Pivot location is between the constrained rigid bodies"),
+ ('ACTIVE', "Active", "Pivot location is at the active object position"),
+ ('SELECTED', "Selected", "Pivot location is at the slected object position")),
+ default='CENTER',)
+
+ @classmethod
+ def poll(cls, context):
+ obj = bpy.context.object
+ objs = bpy.context.selected_objects
+ return (obj and obj.rigid_body and (len(objs) > 1))
+
+ def execute(self, context):
+
+ objs = bpy.context.selected_objects
+ ob_act = bpy.context.active_object
+
+ for ob in objs:
+ if ob == ob_act:
+ continue
+ if self.pivot_type == 'ACTIVE':
+ loc = ob_act.location
+ elif self.pivot_type == 'SELECTED':
+ loc = ob.location
+ else:
+ loc = (ob_act.location + ob.location) / 2
+ bpy.ops.object.add(type='EMPTY', view_align=False, enter_editmode=False, location=loc)
+ bpy.ops.rigidbody.constraint_group_add()
+ con = bpy.context.active_object.rigid_body_constraint
+ con.type = self.con_type
+ con.object1 = ob_act
+ con.object2 = ob
+
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ wm = context.window_manager
+ return wm.invoke_props_dialog(self)
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index 80d9b4f046d..982c723f08e 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -49,6 +49,7 @@ _modules = (
"properties_physics_field",
"properties_physics_fluid",
"properties_physics_rigidbody",
+ "properties_physics_rigidbody_constraint",
"properties_physics_smoke",
"properties_physics_softbody",
"properties_render",
diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py
index 1131ea997da..68c04cfb4c5 100644
--- a/release/scripts/startup/bl_ui/properties_physics_common.py
+++ b/release/scripts/startup/bl_ui/properties_physics_common.py
@@ -88,6 +88,11 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel):
"rigidbody.object_remove",
'MESH_ICOSPHERE') # XXX: need dedicated icon
+ physics_add_special(self, col, ob.rigid_body_constraint, "Rigid Body Constraint",
+ "rigidbody.constraint_add",
+ "rigidbody.constraint_remove",
+ 'CONSTRAINT') # RB_TODO needs better icon
+
# cache-type can be 'PSYS' 'HAIR' 'SMOKE' etc
diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
new file mode 100644
index 00000000000..8bd64d0324a
--- /dev/null
+++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
@@ -0,0 +1,215 @@
+# ##### 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.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import bpy
+from bpy.types import Panel
+
+
+class PHYSICS_PT_rigidbody_constraint_panel():
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "physics"
+
+
+class PHYSICS_PT_rigid_body_constraint(PHYSICS_PT_rigidbody_constraint_panel, Panel):
+ bl_label = "Rigid Body Constraint"
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ rd = context.scene.render
+ return (ob and ob.rigid_body_constraint and (not rd.use_game_engine))
+
+ def draw(self, context):
+ layout = self.layout
+
+ ob = context.object
+ rbc = ob.rigid_body_constraint
+
+ if rbc:
+ layout.prop(rbc, "type")
+
+ split = layout.split()
+
+ row = split.row()
+ row.prop(rbc, "enabled")
+ row.prop(rbc, "disable_collisions")
+
+ split = layout.split()
+ split.prop(rbc, "object1")
+ split = layout.split()
+ split.prop(rbc, "object2")
+
+ split = layout.split()
+ col = split.row()
+ col.prop(rbc, "use_breaking")
+ sub = col.column()
+ sub.active = rbc.use_breaking
+ sub.prop(rbc, "breaking_threshold", text="Threshold")
+
+ split = layout.split()
+ col = split.row()
+ col.prop(rbc, "override_solver_iterations", text="Override Iterations")
+ sub = col.split()
+ sub.active = rbc.override_solver_iterations
+ sub.prop(rbc, "num_solver_iterations", text="Iterations")
+
+ if rbc.type == 'HINGE':
+ col = layout.column(align=True)
+ col.label("Limits:")
+
+ row = col.row()
+ sub = row.row()
+ sub.scale_x = 0.5
+ sub.prop(rbc, "use_limit_ang_z", toggle=True)
+ sub = row.row()
+ sub.active = rbc.use_limit_ang_z
+ sub.prop(rbc, "limit_ang_z_lower", text="Lower")
+ sub.prop(rbc, "limit_ang_z_upper", text="Upper")
+
+ elif rbc.type == 'SLIDER':
+ col = layout.column(align=True)
+ col.label("Limits:")
+
+ row = col.row()
+ sub = row.row()
+ sub.scale_x = 0.5
+ sub.prop(rbc, "use_limit_lin_x", toggle=True)
+ sub = row.row()
+ sub.active = rbc.use_limit_lin_x
+ sub.prop(rbc, "limit_lin_x_lower", text="Lower")
+ sub.prop(rbc, "limit_lin_x_upper", text="Upper")
+
+ elif rbc.type == 'PISTON':
+ col = layout.column(align=True)
+ col.label("Limits:")
+
+ row = col.row()
+ sub = row.row()
+ sub.scale_x = 0.5
+ sub.prop(rbc, "use_limit_lin_x", toggle=True)
+ sub = row.row()
+ sub.active = rbc.use_limit_lin_x
+ sub.prop(rbc, "limit_lin_x_lower", text="Lower")
+ sub.prop(rbc, "limit_lin_x_upper", text="Upper")
+
+ col = layout.column(align=True)
+
+ row = col.row()
+ sub = row.row()
+ sub.scale_x = 0.5
+ sub.prop(rbc, "use_limit_ang_x", toggle=True)
+ sub = row.row()
+ sub.active = rbc.use_limit_ang_x
+ sub.prop(rbc, "limit_ang_x_lower", text="Lower")
+ sub.prop(rbc, "limit_ang_x_upper", text="Upper")
+
+ elif rbc.type in {'GENERIC', 'GENERIC_SPRING'}:
+ col = layout.column(align=True)
+ col.label("Limits:")
+
+ row = col.row()
+ sub = row.row()
+ sub.scale_x = 0.5
+ sub.prop(rbc, "use_limit_lin_x", toggle=True)
+ sub = row.row()
+ sub.active = rbc.use_limit_lin_x
+ sub.prop(rbc, "limit_lin_x_lower", text="Lower")
+ sub.prop(rbc, "limit_lin_x_upper", text="Upper")
+
+ row = col.row()
+ sub = row.row()
+ sub.scale_x = 0.5
+ sub.prop(rbc, "use_limit_lin_y", toggle=True)
+ sub = row.row()
+ sub.active = rbc.use_limit_lin_y
+ sub.prop(rbc, "limit_lin_y_lower", text="Lower")
+ sub.prop(rbc, "limit_lin_y_upper", text="Upper")
+
+ row = col.row()
+ sub = row.row()
+ sub.scale_x = 0.5
+ sub.prop(rbc, "use_limit_lin_z", toggle=True)
+ sub = row.row()
+ sub.active = rbc.use_limit_lin_z
+ sub.prop(rbc, "limit_lin_z_lower", text="Lower")
+ sub.prop(rbc, "limit_lin_z_upper", text="Upper")
+
+ col = layout.column(align=True)
+
+ row = col.row()
+ sub = row.row()
+ sub.scale_x = 0.5
+ sub.prop(rbc, "use_limit_ang_x", toggle=True)
+ sub = row.row()
+ sub.active = rbc.use_limit_ang_x
+ sub.prop(rbc, "limit_ang_x_lower", text="Lower")
+ sub.prop(rbc, "limit_ang_x_upper", text="Upper")
+
+ row = col.row()
+ sub = row.row()
+ sub.scale_x = 0.5
+ sub.prop(rbc, "use_limit_ang_y", toggle=True)
+ sub = row.row()
+ sub.active = rbc.use_limit_ang_y
+ sub.prop(rbc, "limit_ang_y_lower", text="Lower")
+ sub.prop(rbc, "limit_ang_y_upper", text="Upper")
+
+ row = col.row()
+ sub = row.row()
+ sub.scale_x = 0.5
+ sub.prop(rbc, "use_limit_ang_z", toggle=True)
+ sub = row.row()
+ sub.active = rbc.use_limit_ang_z
+ sub.prop(rbc, "limit_ang_z_lower", text="Lower")
+ sub.prop(rbc, "limit_ang_z_upper", text="Upper")
+
+ if rbc.type == 'GENERIC_SPRING':
+ col = layout.column(align=True)
+ col.label("Springs:")
+
+ row = col.row()
+ sub = row.row()
+ sub.scale_x = 0.1
+ sub.prop(rbc, "use_spring_x", toggle=True, text="X")
+ sub = row.row()
+ sub.active = rbc.use_spring_x
+ sub.prop(rbc, "spring_stiffness_x", text="Stiffness")
+ sub.prop(rbc, "spring_damping_x")
+
+ row = col.row()
+ sub = row.row()
+ sub.scale_x = 0.1
+ sub.prop(rbc, "use_spring_y", toggle=True, text="Y")
+ sub = row.row()
+ sub.active = rbc.use_spring_y
+ sub.prop(rbc, "spring_stiffness_y", text="Stiffness")
+ sub.prop(rbc, "spring_damping_y")
+
+ row = col.row()
+ sub = row.row()
+ sub.scale_x = 0.1
+ sub.prop(rbc, "use_spring_z", toggle=True, text="Z")
+ sub = row.row()
+ sub.active = rbc.use_spring_z
+ sub.prop(rbc, "spring_stiffness_z", text="Stiffness")
+ sub.prop(rbc, "spring_damping_z")
+
+if __name__ == "__main__": # only for live edit.
+ bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index ba9b32310b2..ca79c6cb7fa 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -133,6 +133,8 @@ class VIEW3D_PT_tools_rigidbody(View3DPanel, Panel):
col.operator("rigidbody.mass_calculate", text="Calculate Mass")
col.operator("rigidbody.object_settings_copy", text="Copy from Active")
col.operator("rigidbody.bake_to_keyframes", text="Bake To Keyframes")
+ col.label(text="Constraints:")
+ col.operator("rigidbody.connect", text="Connect")
# ********** default tools for editmode_mesh ****************
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);
}