diff options
27 files changed, 1606 insertions, 12 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index 9c6dd0235c5..db3132132da 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -66,6 +66,7 @@ set(SRC_DNA_INC ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_packedFile_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_particle_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_property_types.h + ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_rigidbody_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_scene_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_screen_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sdna_types.h diff --git a/source/blender/SConscript b/source/blender/SConscript index bf52f2e8635..80457c739b6 100644 --- a/source/blender/SConscript +++ b/source/blender/SConscript @@ -61,6 +61,9 @@ if env['WITH_BF_OPENEXR']: if env['WITH_BF_QUICKTIME']: SConscript (['quicktime/SConscript']) +if env['WITH_BF_BULLET']: + SConscript (['rigidbody/SConscript']) + if env['WITH_BF_COLLADA']: SConscript (['collada/SConscript']) diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h new file mode 100644 index 00000000000..26a003841c4 --- /dev/null +++ b/source/blender/blenkernel/BKE_rigidbody.h @@ -0,0 +1,94 @@ +/* + * ***** 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): Joshua Leung, Sergej Reich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BKE_rigidbody.h + * \ingroup blenkernel + * \brief API for Blender-side Rigid Body stuff + */ + + +#ifndef __BKE_RIGIDBODY_H__ +#define __BKE_RIGIDBODY_H__ + +struct RigidBodyWorld; +struct RigidBodyOb; + +struct Scene; +struct Object; +struct Group; + +/* -------------- */ +/* Memory Management */ + +void BKE_rigidbody_free_world(struct RigidBodyWorld *rbw); +void BKE_rigidbody_free_object(struct Object *ob); +void BKE_rigidbody_free_constraint(struct Object *ob); + +/* ...... */ + +struct RigidBodyOb *BKE_rigidbody_copy_object(struct Object *ob); +struct RigidBodyCon *BKE_rigidbody_copy_constraint(struct Object *ob); + +/* -------------- */ +/* Setup */ + +/* create Blender-side settings data - physics objects not initialised yet */ +struct RigidBodyWorld *BKE_rigidbody_create_world(struct Scene *scene); +struct RigidBodyOb *BKE_rigidbody_create_object(struct Scene *scene, struct Object *ob, short type); +struct RigidBodyCon *BKE_rigidbody_create_constraint(struct Scene *scene, struct Object *ob, short type); + +/* 'validate' (i.e. make new or replace old) Physics-Engine objects */ +void BKE_rigidbody_validate_sim_world(struct Scene *scene, struct RigidBodyWorld *rbw, short rebuild); +void BKE_rigidbody_validate_sim_object(struct RigidBodyWorld *rbw, struct Object *ob, short rebuild); +void BKE_rigidbody_validate_sim_shape(struct Object *ob, short rebuild); +void BKE_rigidbody_validate_sim_constraint(struct RigidBodyWorld *rbw, struct Object *ob, short rebuild); + +/* -------------- */ +/* Utilities */ + +struct RigidBodyWorld *BKE_rigidbody_get_world(struct Scene *scene); +void BKE_rigidbody_remove_object(struct Scene *scene, struct Object *ob); +void BKE_rigidbody_remove_constraint(struct Scene *scene, struct Object *ob); + +/* -------------- */ +/* Utility Macros */ + +/* get mass of Rigid Body Object to supply to RigidBody simulators */ +#define RBO_GET_MASS(rbo) \ + ((rbo && ((rbo->type == RBO_TYPE_PASSIVE) || (rbo->flag & RBO_FLAG_KINEMATIC) || (rbo->flag & RBO_FLAG_DISABLED))) ? (0.0f) : (rbo->mass)) +/* get collision margin for Rigid Body Object, triangle mesh and cone shapes cannot embed margin, convex hull always uses custom margin */ +#define RBO_GET_MARGIN(rbo) \ + ((rbo->flag & RBO_FLAG_USE_MARGIN || rbo->shape == RB_SHAPE_CONVEXH || rbo->shape == RB_SHAPE_TRIMESH || rbo->shape == RB_SHAPE_CONE) ? (rbo->margin) : (0.04f)) + +/* -------------- */ +/* Simulation */ + +void BKE_rigidbody_sync_transforms(struct Scene *scene, struct Object *ob, float ctime); +void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw); +void BKE_rigidbody_do_simulation(struct Scene *scene, float ctime); + +#endif /* __BKE_RIGIDBODY_H__ */ diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 6447b2a8dee..2ac32a3f651 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -72,6 +72,7 @@ struct Scene *BKE_scene_add(struct Main *bmain, const char *name); /* base functions */ struct Base *BKE_scene_base_find(struct Scene *scene, struct Object *ob); struct Base *BKE_scene_base_add(struct Scene *sce, struct Object *ob); +void BKE_scene_base_remove(struct Scene *sce, struct Base *base); void BKE_scene_base_deselect_all(struct Scene *sce); void BKE_scene_base_select(struct Scene *sce, struct Base *selbase); int BKE_scene_base_iter_next(struct Scene **scene, int val, struct Base **base, struct Object **ob); @@ -115,6 +116,7 @@ int BKE_scene_use_new_shading_nodes(struct Scene *scene); void BKE_scene_disable_color_management(struct Scene *scene); int BKE_scene_check_color_management_enabled(const struct Scene *scene); +int BKE_scene_check_rigidbody_active(const struct Scene *scene); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index aca06a1abcf..846ed8a9bb4 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -37,6 +37,7 @@ set(INC ../modifiers ../nodes ../render/extern/include + ../rigidbody ../../../intern/guardedalloc ../../../intern/iksolver/extern ../../../intern/memutil @@ -128,6 +129,7 @@ set(SRC intern/pointcache.c intern/property.c intern/report.c + intern/rigidbody.c intern/sca.c intern/scene.c intern/screen.c @@ -219,6 +221,7 @@ set(SRC BKE_pointcache.h BKE_property.h BKE_report.h + BKE_rigidbody.h BKE_sca.h BKE_scene.h BKE_screen.h diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index 0286172e639..b146235d63c 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -41,6 +41,7 @@ incs += ' ../render/extern/include ../makesrna' incs += ' ../imbuf ../ikplugin ../avi #/intern/elbeem/extern ../nodes ../modifiers' incs += ' #/intern/iksolver/extern ../blenloader' incs += ' #/extern/bullet2/src' +incs += ' ../rigidbody' incs += ' #/intern/opennl/extern #/intern/bsp/extern' incs += ' ../gpu #/extern/glew/include' incs += ' ../bmesh' diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 42389564ec0..78d7bfa5bc5 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -2290,7 +2290,7 @@ static short animdata_use_time(AnimData *adt) return 0; } -static void dag_object_time_update_flags(Object *ob) +static void dag_object_time_update_flags(Scene *scene, Object *ob) { if (ob->constraints.first) { bConstraint *con; @@ -2350,6 +2350,9 @@ static void dag_object_time_update_flags(Object *ob) if (object_modifiers_use_time(ob)) ob->recalc |= OB_RECALC_DATA; if ((ob->pose) && (ob->pose->flag & POSE_CONSTRAINTS_TIMEDEPEND)) ob->recalc |= OB_RECALC_DATA; + if (ob->rigidbody_object && BKE_scene_check_rigidbody_active(scene)) + ob->recalc |= OB_RECALC_OB; + { AnimData *adt = BKE_animdata_from_id((ID *)ob->data); Mesh *me; @@ -2434,7 +2437,7 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const s if (do_time) { /* now if DagNode were part of base, the node->lay could be checked... */ /* we do all now, since the scene_flush checks layers and clears recalc flags even */ - dag_object_time_update_flags(ob); + dag_object_time_update_flags(scene, ob); } /* handled in next loop */ @@ -2447,7 +2450,7 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const s for (group = bmain->group.first; group; group = group->id.next) { if (group->id.flag & LIB_DOIT) { for (go = group->gobject.first; go; go = go->next) { - dag_object_time_update_flags(go->ob); + dag_object_time_update_flags(scene, go->ob); } } } @@ -2466,7 +2469,7 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const s /* hrmf... an exception to look at once, for invisible camera object we do it over */ if (scene->camera) - dag_object_time_update_flags(scene->camera); + dag_object_time_update_flags(scene, scene->camera); } /* and store the info in groupobject */ diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 05031ddc142..2738c546ce1 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -98,6 +98,7 @@ #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_property.h" +#include "BKE_rigidbody.h" #include "BKE_sca.h" #include "BKE_scene.h" #include "BKE_sequencer.h" @@ -386,6 +387,7 @@ void BKE_object_free(Object *ob) BKE_free_constraints(&ob->constraints); free_partdeflect(ob->pd); + BKE_rigidbody_free_object(ob); if (ob->soft) sbFree(ob->soft); if (ob->bsoft) bsbFree(ob->bsoft); @@ -1288,6 +1290,7 @@ static Object *object_copy_do(Object *ob, int copy_caches) obn->bsoft = copy_bulletsoftbody(ob->bsoft); 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/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c new file mode 100644 index 00000000000..e6f6c9a9a98 --- /dev/null +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -0,0 +1,718 @@ +/* + * ***** 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): Joshua Leung, Sergej Reich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file rigidbody.c + * \ingroup blenkernel + * \brief Blender-side interface and methods for dealing with Rigid Body simulations + */ + +#include <stdio.h> +#include <string.h> +#include <stddef.h> +#include <float.h> +#include <math.h> +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" + +#include "RBI_api.h" + +#include "DNA_anim_types.h" +#include "DNA_group_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_rigidbody_types.h" +#include "DNA_scene_types.h" + +#include "BKE_animsys.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_effect.h" +#include "BKE_group.h" +#include "BKE_object.h" +#include "BKE_mesh.h" +#include "BKE_pointcache.h" +#include "BKE_rigidbody.h" +#include "BKE_global.h" +#include "BKE_utildefines.h" + +#include "RNA_access.h" + +/* ************************************** */ +/* Memory Management */ + +/* Freeing Methods --------------------- */ + +/* 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 */ + if (rbw->group) { + for (go = rbw->group->gobject.first; go; go = go->next) { + if (go->ob && go->ob->rigidbody_object) { + RigidBodyOb *rbo = go->ob->rigidbody_object; + + if (rbo->physics_object) + RB_dworld_remove_body(rbw->physics_world, rbo->physics_object); + } + } + } + /* free dynamics world */ + RB_dworld_delete(rbw->physics_world); + } + if (rbw->objects) + free(rbw->objects); + + /* free rigidbody world itself */ + MEM_freeN(rbw); +} + +/* Free RigidBody settings and sim instances */ +void BKE_rigidbody_free_object(Object *ob) +{ + RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL; + + /* sanity check */ + if (rbo == NULL) + return; + + /* free physics references */ + if (rbo->physics_object) { + RB_body_delete(rbo->physics_object); + rbo->physics_object = NULL; + } + + if (rbo->physics_shape) { + RB_shape_delete(rbo->physics_shape); + rbo->physics_shape = NULL; + } + + /* free data itself */ + MEM_freeN(rbo); + ob->rigidbody_object = NULL; +} + +/* Copying Methods --------------------- */ + +/* These just copy the data, clearing out references to physics objects. + * Anything that uses them MUST verify that the copied object will + * be added to relevant groups later... + */ + +RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) +{ + RigidBodyOb *rboN = NULL; + + if (ob->rigidbody_object) { + /* just duplicate the whole struct first (to catch all the settings) */ + rboN = MEM_dupallocN(ob->rigidbody_object); + + /* tag object as needing to be verified */ + rboN->flag |= RBO_FLAG_NEEDS_VALIDATE; + + /* clear out all the fields which need to be revalidated later */ + rboN->physics_object = NULL; + rboN->physics_shape = NULL; + } + + /* return new copy of settings */ + return rboN; +} + +/* ************************************** */ +/* Setup Utilities - Validate Sim Instances */ + +/* create collision shape of mesh - convex hull */ +static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, float margin, bool *can_embed) +{ + rbCollisionShape *shape = NULL; + Mesh *me = NULL; + + if (ob->type == OB_MESH && ob->data) { + me = ob->data; + } + else { + printf("ERROR: cannot make Convex Hull collision shape for non-Mesh object\n"); + } + + if (me && me->totvert) { + shape = RB_shape_new_convex_hull((float *)me->mvert, sizeof(MVert), me->totvert, margin, can_embed); + } + else { + printf("ERROR: no vertices to define Convex Hull collision shape with\n"); + } + + return shape; +} + +/* create collision shape of mesh - triangulated mesh + * returns NULL if creation fails. + */ +static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob) +{ + rbCollisionShape *shape = NULL; + + if (ob->type == OB_MESH) { + DerivedMesh *dm = CDDM_from_mesh(ob->data, ob); + + MVert *mvert; + MFace *mface; + int totvert; + int totface; + + /* ensure mesh validity, then grab data */ + DM_ensure_tessface(dm); + + mvert = (dm) ? dm->getVertArray(dm) : NULL; + totvert = (dm) ? dm->getNumVerts(dm) : 0; + mface = (dm) ? dm->getTessFaceArray(dm) : NULL; + totface = (dm) ? dm->getNumTessFaces(dm) : 0; + + /* sanity checking - potential case when no data will be present */ + if ((totvert == 0) || (totface == 0)) { + printf("WARNING: no geometry data converted for Mesh Collision Shape (ob = %s)\n", ob->id.name + 2); + } + else { + rbMeshData *mdata; + int i; + + /* init mesh data for collision shape */ + mdata = RB_trimesh_data_new(); + + /* loop over all faces, adding them as triangles to the collision shape + * (so for some faces, more than triangle will get added) + */ + for (i = 0; (i < totface) && (mface) && (mvert); i++, mface++) { + /* add first triangle - verts 1,2,3 */ + { + MVert *va = (IN_RANGE(mface->v1, 0, totvert)) ? (mvert + mface->v1) : (mvert); + MVert *vb = (IN_RANGE(mface->v2, 0, totvert)) ? (mvert + mface->v2) : (mvert); + MVert *vc = (IN_RANGE(mface->v3, 0, totvert)) ? (mvert + mface->v3) : (mvert); + + RB_trimesh_add_triangle(mdata, va->co, vb->co, vc->co); + } + + /* add second triangle if needed - verts 1,3,4 */ + if (mface->v4) { + MVert *va = (IN_RANGE(mface->v1, 0, totvert)) ? (mvert + mface->v1) : (mvert); + MVert *vb = (IN_RANGE(mface->v3, 0, totvert)) ? (mvert + mface->v3) : (mvert); + MVert *vc = (IN_RANGE(mface->v4, 0, totvert)) ? (mvert + mface->v4) : (mvert); + + RB_trimesh_add_triangle(mdata, va->co, vb->co, vc->co); + } + } + + /* construct collision shape + * + * These have been chosen to get better speed/accuracy tradeoffs with regards + * to limitations of each: + * - BVH-Triangle Mesh: for passive objects only. Despite having greater + * speed/accuracy, they cannot be used for moving objects. + * - GImpact Mesh: for active objects. These are slower and less stable, + * but are more flexible for general usage. + */ + if (ob->rigidbody_object->type == RBO_TYPE_PASSIVE) { + shape = RB_shape_new_trimesh(mdata); + } + else { + shape = RB_shape_new_gimpact_mesh(mdata); + } + } + + /* cleanup temp data */ + if (dm) { + dm->release(dm); + } + } + else { + printf("ERROR: cannot make Triangular Mesh collision shape for non-Mesh object\n"); + } + + return shape; +} + +/* Create new physics sim collision shape for object and store it, + * or remove the existing one first and replace... + */ +void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild) +{ + RigidBodyOb *rbo = ob->rigidbody_object; + rbCollisionShape *new_shape = NULL; + BoundBox *bb = NULL; + float size[3] = {1.0f, 1.0f, 1.0f}; + float radius = 1.0f; + float height = 1.0f; + float capsule_height; + float hull_margin = 0.0f; + bool can_embed = true; + + /* sanity check */ + if (rbo == NULL) + return; + + /* don't create a new shape if we already have one and don't want to rebuild it */ + if (rbo->physics_shape && !rebuild) + return; + + /* if automatically determining dimensions, use the Object's boundbox + * - assume that all quadrics are standing upright on local z-axis + * - assume even distribution of mass around the Object's pivot + * (i.e. Object pivot is centralised in boundbox) + */ + // XXX: all dimensions are auto-determined now... later can add stored settings for this + /* get object dimensions without scaling */ + bb = BKE_object_boundbox_get(ob); + if (bb) { + size[0] = (bb->vec[4][0] - bb->vec[0][0]); + size[1] = (bb->vec[2][1] - bb->vec[0][1]); + size[2] = (bb->vec[1][2] - bb->vec[0][2]); + } + mul_v3_fl(size, 0.5f); + + if (ELEM3(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { + /* take radius as largest x/y dimension, and height as z-dimension */ + radius = MAX2(size[0], size[1]); + height = size[2]; + } + else if (rbo->shape == RB_SHAPE_SPHERE) { + /* take radius to the the largest dimension to try and encompass everything */ + radius = MAX3(size[0], size[1], size[2]); + } + + /* create new shape */ + switch (rbo->shape) { + case RB_SHAPE_BOX: + new_shape = RB_shape_new_box(size[0], size[1], size[2]); + break; + + case RB_SHAPE_SPHERE: + new_shape = RB_shape_new_sphere(radius); + break; + + case RB_SHAPE_CAPSULE: + capsule_height = (height - radius) * 2.0f; + new_shape = RB_shape_new_capsule(radius, (capsule_height > 0.0f) ? capsule_height : 0.0f); + break; + case RB_SHAPE_CYLINDER: + new_shape = RB_shape_new_cylinder(radius, height); + break; + case RB_SHAPE_CONE: + new_shape = RB_shape_new_cone(radius, height * 2.0f); + break; + + case RB_SHAPE_CONVEXH: + /* try to emged collision margin */ + if (!(rbo->flag & RBO_FLAG_USE_MARGIN)) + hull_margin = 0.04f; + new_shape = rigidbody_get_shape_convexhull_from_mesh(ob, hull_margin, &can_embed); + if (!(rbo->flag & RBO_FLAG_USE_MARGIN)) + rbo->margin = (can_embed) ? 0.04f : 0.0f; /* RB_TODO ideally we shouldn't directly change the margin here */ + break; + case RB_SHAPE_TRIMESH: + new_shape = rigidbody_get_shape_trimesh_from_mesh(ob); + break; + } + /* assign new collision shape if creation was successful */ + if (new_shape) { + if (rbo->physics_shape) + RB_shape_delete(rbo->physics_shape); + rbo->physics_shape = new_shape; + RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo)); + } +} + +/* --------------------- */ + +/* Create physics sim representation of object given RigidBody settings + * < rebuild: even if an instance already exists, replace it + */ +void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short rebuild) +{ + RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL; + float loc[3]; + float rot[4]; + + /* sanity checks: + * - object doesn't have RigidBody info already: then why is it here? + */ + if (rbo == NULL) + return; + + /* make sure collision shape exists */ + if (rbo->physics_shape == NULL || rebuild) + BKE_rigidbody_validate_sim_shape(ob, true); + + if (rbo->physics_object) { + if (rebuild == false) + RB_dworld_remove_body(rbw->physics_world, rbo->physics_object); + } + if (!rbo->physics_object || rebuild) { + /* remove rigid body if it already exists before creating a new one */ + if (rbo->physics_object) { + RB_body_delete(rbo->physics_object); + } + + mat4_to_loc_quat(loc, rot, ob->obmat); + + rbo->physics_object = RB_body_new(rbo->physics_shape, loc, rot); + + RB_body_set_friction(rbo->physics_object, rbo->friction); + RB_body_set_restitution(rbo->physics_object, rbo->restitution); + + RB_body_set_damping(rbo->physics_object, rbo->lin_damping, rbo->ang_damping); + RB_body_set_sleep_thresh(rbo->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh); + RB_body_set_activation_state(rbo->physics_object, rbo->flag & RBO_FLAG_USE_DEACTIVATION); + + if (rbo->type == RBO_TYPE_PASSIVE || rbo->flag & RBO_FLAG_START_DEACTIVATED) + RB_body_deactivate(rbo->physics_object); + + + RB_body_set_linear_factor(rbo->physics_object, + (ob->protectflag & OB_LOCK_LOCX) == 0, + (ob->protectflag & OB_LOCK_LOCY) == 0, + (ob->protectflag & OB_LOCK_LOCZ) == 0); + RB_body_set_angular_factor(rbo->physics_object, + (ob->protectflag & OB_LOCK_ROTX) == 0, + (ob->protectflag & OB_LOCK_ROTY) == 0, + (ob->protectflag & OB_LOCK_ROTZ) == 0); + + RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); + RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED); + } + + if (rbw && rbw->physics_world) + RB_dworld_add_body(rbw->physics_world, rbo->physics_object, rbo->col_groups); +} + +/* --------------------- */ + +/* 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) +{ + /* sanity checks */ + if (rbw == NULL) + return; + + /* create new sim world */ + if (rebuild || rbw->physics_world == NULL) { + if (rbw->physics_world) + RB_dworld_delete(rbw->physics_world); + rbw->physics_world = RB_dworld_new(scene->physics_settings.gravity); + } + + RB_dworld_set_solver_iterations(rbw->physics_world, rbw->num_solver_iterations); + RB_dworld_set_split_impulse(rbw->physics_world, rbw->flag & RBW_FLAG_USE_SPLIT_IMPULSE); +} + +/* ************************************** */ +/* Setup Utilities - Create Settings Blocks */ + +/* Set up RigidBody world */ +RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) +{ + /* try to get whatever RigidBody world that might be representing this already */ + RigidBodyWorld *rbw; + + /* sanity checks + * - there must be a valid scene to add world to + * - there mustn't be a sim world using this group already + */ + if (scene == NULL) + return NULL; + + /* create a new sim world */ + rbw = MEM_callocN(sizeof(RigidBodyWorld), "RigidBodyWorld"); + + /* set default settings */ + rbw->ltime = PSFRA; + + rbw->time_scale = 1.0f; + + rbw->steps_per_second = 60; /* Bullet default (60 Hz) */ + rbw->num_solver_iterations = 10; /* 10 is bullet default */ + + /* return this sim world */ + return rbw; +} + +/* Add rigid body settings to the specified object */ +RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) +{ + RigidBodyOb *rbo; + RigidBodyWorld *rbw = scene->rigidbody_world; + + /* sanity checks + * - rigidbody world must exist + * - object must exist + * - cannot add rigid body if it already exists + */ + if (ob == NULL || (ob->rigidbody_object != NULL)) + return NULL; + + /* create new settings data, and link it up */ + rbo = MEM_callocN(sizeof(RigidBodyOb), "RigidBodyOb"); + + /* set default settings */ + rbo->type = type; + + rbo->mass = 1.0f; + + rbo->friction = 0.5f; /* best when non-zero. 0.5 is Bullet default */ + rbo->restitution = 0.0f; /* best when zero. 0.0 is Bullet default */ + + rbo->margin = 0.04f; /* 0.04 (in meters) is Bullet default */ + + rbo->lin_sleep_thresh = 0.4f; /* 0.4 is half of Bullet default */ + rbo->ang_sleep_thresh = 0.5f; /* 0.5 is half of Bullet default */ + + rbo->lin_damping = 0.04f; /* 0.04 is game engine default */ + rbo->ang_damping = 0.1f; /* 0.1 is game engine default */ + + rbo->col_groups = 1; + + /* use triangle meshes for passive objects + * use convex hulls for active objects since dynamic triangle meshes are very unstable + */ + if (type == RBO_TYPE_ACTIVE) + rbo->shape = RB_SHAPE_CONVEXH; + else + rbo->shape = RB_SHAPE_TRIMESH; + + /* set initial transform */ + mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat); + + /* flag cache as outdated */ + BKE_rigidbody_cache_reset(rbw); + + /* return this object */ + return rbo; +} + +/* ************************************** */ +/* Utilities API */ + +/* Get RigidBody world for the given scene, creating one if needed + * < scene: Scene to find active Rigid Body world for + */ +RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) +{ + /* sanity check */ + if (scene == NULL) + return NULL; + + return scene->rigidbody_world; +} + +void BKE_rigidbody_remove_object(Scene *scene, Object *ob) +{ + RigidBodyWorld *rbw = scene->rigidbody_world; + RigidBodyOb *rbo = ob->rigidbody_object; + GroupObject *go; + int i; + + if (rbw) { + /* remove from rigidbody world, free object won't do this */ + if (rbw->physics_world && rbo->physics_object) + RB_dworld_remove_body(rbw->physics_world, rbo->physics_object); + + /* remove object from array */ + if (rbw && rbw->objects) { + for (i = 0; i < rbw->numbodies; i++) { + if (rbw->objects[i] == ob) { + rbw->objects[i] = NULL; + break; + } + } + } + } + /* remove object's settings */ + BKE_rigidbody_free_object(ob); + /* flag cache as outdated */ + BKE_rigidbody_cache_reset(rbw); +} + + +/* ************************************** */ +/* Simulation Interface - Bullet */ + +/* Update object array and rigid body count so they're in sync with the rigid body group */ +static void rigidbody_update_ob_array(RigidBodyWorld *rbw) +{ + GroupObject *go; + int i, n; + + n = BLI_countlist(&rbw->group->gobject); + + if (rbw->numbodies != n) { + rbw->numbodies = n; + rbw->objects = realloc(rbw->objects, sizeof(Object *) * rbw->numbodies); + } + + for (go = rbw->group->gobject.first, i = 0; go; go = go->next, i++) { + Object *ob = go->ob; + rbw->objects[i] = ob; + } +} + +static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw) +{ + float adj_gravity[3]; + + /* adjust gravity to take effector weights into account */ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(adj_gravity, scene->physics_settings.gravity); + } + else { + zero_v3(adj_gravity); + } + + /* update gravity, since this RNA setting is not part of RigidBody settings */ + RB_dworld_set_gravity(rbw->physics_world, adj_gravity); + + /* update object array in case there are changes */ + rigidbody_update_ob_array(rbw); +} + +static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo) +{ + float loc[3]; + float rot[4]; + float scale[3]; + + /* only update if rigid body exists */ + if (rbo->physics_object == NULL) + return; + + mat4_decompose(loc, rot, scale, ob->obmat); + + /* update scale for all objects */ + RB_body_set_scale(rbo->physics_object, scale); + /* compensate for embedded convex hull collision margin */ + if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && rbo->shape == RB_SHAPE_CONVEXH) + RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2])); + + /* update rigid body location and rotation for kinematic bodies */ + if (rbo->flag & RBO_FLAG_KINEMATIC) { + RB_body_activate(rbo->physics_object); + RB_body_set_loc_rot(rbo->physics_object, loc, rot); + } + /* NOTE: passive objects don't need to be updated since they don't move */ + + /* NOTE: no other settings need to be explicitly updated here, + * since RNA setters take care of the rest :) + */ +} + +/* Updates and validates world, bodies and shapes. + * < rebuild: rebuild entire simulation + */ +static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int rebuild) +{ + GroupObject *go; + + /* update world */ + if (rebuild) + BKE_rigidbody_validate_sim_world(scene, rbw, true); + rigidbody_update_sim_world(scene, rbw); + + /* update objects */ + for (go = rbw->group->gobject.first; go; go = go->next) { + Object *ob = go->ob; + + if (ob && ob->type == OB_MESH) { + /* validate that we've got valid object set up here... */ + RigidBodyOb *rbo = ob->rigidbody_object; + /* 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 (rbo == NULL) { + /* Since this object is included in the sim group but doesn't have + * rigid body settings (perhaps it was added manually), add! + * - assume object to be active? That is the default for newly added settings... + */ + ob->rigidbody_object = BKE_rigidbody_create_object(scene, ob, RBO_TYPE_ACTIVE); + BKE_rigidbody_validate_sim_object(rbw, ob, true); + + rbo = ob->rigidbody_object; + } + else { + /* perform simulation data updates as tagged */ + /* refresh object... */ + if (rebuild) { + /* World has been rebuilt so rebuild object */ + BKE_rigidbody_validate_sim_object(rbw, ob, true); + } + else if (rbo->flag & RBO_FLAG_NEEDS_VALIDATE) { + BKE_rigidbody_validate_sim_object(rbw, ob, false); + } + /* refresh shape... */ + if (rbo->flag & RBO_FLAG_NEEDS_RESHAPE) { + /* mesh/shape data changed, so force shape refresh */ + BKE_rigidbody_validate_sim_shape(ob, true); + /* now tell RB sim about it */ + // XXX: we assume that this can only get applied for active/passive shapes that will be included as rigidbodies + RB_body_set_collision_shape(rbo->physics_object, rbo->physics_shape); + } + rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE); + } + + /* update simulation object... */ + rigidbody_update_sim_ob(scene, rbw, ob, rbo); + } + } +} + +/* Sync rigid body and object transformations */ +void BKE_rigidbody_sync_transforms(Scene *scene, Object *ob, float ctime) +{ +// RB_TODO implement this +} + +void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) +{ +// RB_TODO implement this +} + +/* ------------------ */ + +/* Run RigidBody simulation for the specified physics world */ +void BKE_rigidbody_do_simulation(Scene *scene, float ctime) +{ +// RB_TODO implement this +} +/* ************************************** */ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 9cf0724f82a..e48cf369d4f 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -46,6 +46,7 @@ #include "DNA_group_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" +#include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_sequence_types.h" @@ -72,6 +73,7 @@ #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_pointcache.h" +#include "BKE_rigidbody.h" #include "BKE_scene.h" #include "BKE_sequencer.h" #include "BKE_world.h" @@ -310,6 +312,9 @@ void BKE_scene_free(Scene *sce) BKE_free_animdata((ID *)sce); BKE_keyingsets_free(&sce->keyingsets); + if (sce->rigidbody_world) + BKE_rigidbody_free_world(sce->rigidbody_world); + if (sce->r.avicodecdata) { free_avicodecdata(sce->r.avicodecdata); MEM_freeN(sce->r.avicodecdata); @@ -936,6 +941,16 @@ Base *BKE_scene_base_add(Scene *sce, Object *ob) return b; } +void BKE_scene_base_remove(Scene *sce, Base *base) +{ + /* remove rigid body object from world before removing object */ + if (base->object->rigidbody_object) + BKE_rigidbody_remove_object(sce, base->object); + + BLI_remlink(&sce->base, base); + MEM_freeN(base); +} + void BKE_scene_base_deselect_all(Scene *sce) { Base *b; @@ -1376,3 +1391,8 @@ int BKE_scene_check_color_management_enabled(const Scene *scene) { return strcmp(scene->display_settings.display_device, "None") != 0; } + +int BKE_scene_check_rigidbody_active(const Scene *scene) +{ + return scene && scene->rigidbody_world && scene->rigidbody_world->group && !(scene->rigidbody_world->flag & RBW_FLAG_MUTED); +} diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index d042e43f9ca..95fa4018392 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -81,6 +81,7 @@ #include "DNA_packedFile_types.h" #include "DNA_particle_types.h" #include "DNA_property_types.h" +#include "DNA_rigidbody_types.h" #include "DNA_text_types.h" #include "DNA_view3d_types.h" #include "DNA_screen_types.h" @@ -4785,7 +4786,18 @@ static void direct_link_object(FileData *fd, Object *ob) } ob->bsoft = newdataadr(fd, ob->bsoft); ob->fluidsimSettings= newdataadr(fd, ob->fluidsimSettings); /* NT */ - + + ob->rigidbody_object = newdataadr(fd, ob->rigidbody_object); + if (ob->rigidbody_object) { + RigidBodyOb *rbo = ob->rigidbody_object; + + /* must nullify the references to physics sim objects, since they no-longer exist + * (and will need to be recalculated) + */ + rbo->physics_object = NULL; + rbo->physics_shape = NULL; + } + link_list(fd, &ob->particlesystem); direct_link_particlesystems(fd, &ob->particlesystem); @@ -5003,6 +5015,14 @@ static void lib_link_scene(FileData *fd, Main *main) BKE_sequencer_update_muting(sce->ed); BKE_sequencer_update_sound_bounds_all(sce); + + /* rigidbody world relies on it's linked groups */ + if (sce->rigidbody_world) { + RigidBodyWorld *rbw = sce->rigidbody_world; + if (rbw->group) + rbw->group = newlibadr(fd, sce->id.lib, rbw->group); + } + if (sce->nodetree) { lib_link_ntree(fd, &sce->id, sce->nodetree); composite_patch(sce->nodetree, sce); @@ -5079,6 +5099,7 @@ static void direct_link_scene(FileData *fd, Scene *sce) Editing *ed; Sequence *seq; MetaStack *ms; + RigidBodyWorld *rbw; sce->theDag = NULL; sce->dagisvalid = 0; @@ -5265,6 +5286,17 @@ static void direct_link_scene(FileData *fd, Scene *sce) } direct_link_view_settings(fd, &sce->view_settings); + + sce->rigidbody_world = newdataadr(fd, sce->rigidbody_world); + rbw = sce->rigidbody_world; + if (rbw) { + /* must nullify the reference to physics sim object, since it no-longer exist + * (and will need to be recalculated) + */ + rbw->physics_world = NULL; + rbw->objects = NULL; + rbw->numbodies = 0; + } } /* ************ READ WM ***************** */ @@ -9680,6 +9712,10 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce) } SEQ_END } + + if (sce->rigidbody_world) { + expand_doit(fd, mainvar, sce->rigidbody_world->group); + } #ifdef DURIAN_CAMERA_SWITCH { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ef0c5b0e6bd..a52e4e28981 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -118,6 +118,7 @@ #include "DNA_packedFile_types.h" #include "DNA_particle_types.h" #include "DNA_property_types.h" +#include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" #include "DNA_sdna_types.h" #include "DNA_sequence_types.h" @@ -1487,6 +1488,11 @@ static void write_objects(WriteData *wd, ListBase *idbase) } writestruct(wd, DATA, "BulletSoftBody", 1, ob->bsoft); + if (ob->rigidbody_object) { + // TODO: if any extra data is added to handle duplis, will need separate function then + writestruct(wd, DATA, "RigidBodyOb", 1, ob->rigidbody_object); + } + write_particlesystems(wd, &ob->particlesystem); write_modifiers(wd, &ob->modifiers); } @@ -2296,7 +2302,12 @@ static void write_scenes(WriteData *wd, ListBase *scebase) } write_view_settings(wd, &sce->view_settings); - + + /* writing RigidBodyWorld data to the blend file */ + if (sce->rigidbody_world) { + writestruct(wd, DATA, "RigidBodyWorld", 1, sce->rigidbody_world); + } + sce= sce->id.next; } /* flush helps the compression for undo-save */ diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 4db416b6f72..897aeb74482 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -941,11 +941,10 @@ static void object_delete_check_glsl_update(Object *ob) void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Base *base) { DAG_id_type_tag(bmain, ID_OB); - BLI_remlink(&scene->base, base); + BKE_scene_base_remove(scene, base); object_delete_check_glsl_update(base->object); BKE_libblock_free_us(&bmain->object, base->object); if (scene->basact == base) scene->basact = NULL; - MEM_freeN(base); } static int object_delete_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index fa44d3d7fb4..68d7dcafd9c 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -354,8 +354,7 @@ static int make_proxy_exec(bContext *C, wmOperator *op) /* remove base, leave user count of object, it gets linked in BKE_object_make_proxy */ if (gob == NULL) { - BLI_remlink(&scene->base, oldbase); - MEM_freeN(oldbase); + BKE_scene_base_remove(scene, oldbase); } BKE_object_make_proxy(newob, ob, gob); diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 6cf7133cb4d..16859e5975a 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -56,6 +56,7 @@ struct ParticleSystem; struct DerivedMesh; struct SculptSession; struct bGPdata; +struct RigidBodyOb; /* Vertex Groups - Name Info */ @@ -270,6 +271,8 @@ typedef struct Object { ListBase gpulamp; /* runtime, for glsl lamp display only */ ListBase pc_ids; ListBase *duplilist; /* for temporary dupli list storage, only for use by RNA API */ + + struct RigidBodyOb *rigidbody_object; /* settings for Bullet rigid body */ 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 new file mode 100644 index 00000000000..8c66a5b2333 --- /dev/null +++ b/source/blender/makesdna/DNA_rigidbody_types.h @@ -0,0 +1,171 @@ +/* + * ***** 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): Joshua Leung, Sergej Reich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file DNA_rigidbody_types.h + * \ingroup DNA + * \brief Types and defines for representing Rigid Body entities + */ + +#ifndef __DNA_RIGIDBODY_TYPES_H__ +#define __DNA_RIGIDBODY_TYPES_H__ + +#include "DNA_listBase.h" + +struct Group; + +/* ******************************** */ +/* RigidBody World */ + +/* RigidBodyWorld (rbw) + * + * Represents a "simulation scene" existing within the parent scene. + */ +typedef struct RigidBodyWorld { + /* Sim World Settings ------------------------------------------------------------- */ + 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 */ + + int pad; + float ltime; /* last frame world was evaluated for (internal) */ + + /* cache */ + int numbodies; /* number of objects in rigid body group */ + + short steps_per_second; /* number of simulation steps thaken per second */ + short num_solver_iterations;/* number of constraint solver iterations made per simulation step */ + + int flag; /* (eRigidBodyWorld_Flag) settings for this RigidBodyWorld */ + float time_scale; /* used to speed up or slow down the simulation */ + + /* References to Physics Sim objects. Exist at runtime only ---------------------- */ + void *physics_world; /* Physics sim world (i.e. btDiscreteDynamicsWorld) */ +} RigidBodyWorld; + +/* Flags for RigidBodyWorld */ +typedef enum eRigidBodyWorld_Flag { + /* should sim world be skipped when evaluating (user setting) */ + RBW_FLAG_MUTED = (1<<0), + /* sim data needs to be rebuilt */ + RBW_FLAG_NEEDS_REBUILD = (1<<1), + /* usse split impulse when stepping the simulation */ + RBW_FLAG_USE_SPLIT_IMPULSE = (1<<2) +} eRigidBodyWorld_Flag; + +/* ******************************** */ +/* RigidBody Object */ + +/* RigidBodyObject (rbo) + * + * Represents an object participating in a RigidBody sim. + * This is attached to each object that is currently + * participating in a sim. + */ +typedef struct RigidBodyOb { + /* References to Physics Sim objects. Exist at runtime only */ + void *physics_object; /* Physics object representation (i.e. btRigidBody) */ + void *physics_shape; /* Collision shape used by physics sim (i.e. btCollisionShape) */ + + /* General Settings for this RigidBodyOb */ + short type; /* (eRigidBodyOb_Type) role of RigidBody in sim */ + short shape; /* (eRigidBody_Shape) collision shape to use */ + + int flag; /* (eRigidBodyOb_Flag) */ + int col_groups; /* Collision groups that determines wich rigid bodies can collide with each other */ + int pad; + + /* Physics Parameters */ + float mass; /* how much object 'weighs' (i.e. absolute 'amount of stuff' it holds) */ + + float friction; /* resistance of object to movement */ + float restitution; /* how 'bouncy' object is when it collides */ + + float margin; /* tolerance for detecting collisions */ + + float lin_damping; /* damping for linear velocities */ + float ang_damping; /* damping for angular velocities */ + + float lin_sleep_thresh; /* deactivation threshold for linear velocities */ + float ang_sleep_thresh; /* deactivation threshold for angular velocities */ + + float orn[4]; /* rigid body orientation */ + float pos[3]; /* rigid body position */ + float pad1; +} RigidBodyOb; + + +/* Participation types for RigidBodyOb */ +typedef enum eRigidBodyOb_Type { + /* active geometry participant in simulation. is directly controlled by sim */ + RBO_TYPE_ACTIVE = 0, + /* passive geometry participant in simulation. is directly controlled by animsys */ + RBO_TYPE_PASSIVE +} eRigidBodyOb_Type; + +/* Flags for RigidBodyOb */ +typedef enum eRigidBodyOb_Flag { + /* rigidbody is kinematic (controlled by the animation system) */ + RBO_FLAG_KINEMATIC = (1<<0), + /* rigidbody needs to be validated (usually set after duplicating and not hooked up yet) */ + RBO_FLAG_NEEDS_VALIDATE = (1<<1), + /* rigidbody shape needs refreshing (usually after exiting editmode) */ + RBO_FLAG_NEEDS_RESHAPE = (1<<2), + /* rigidbody can be deactivated */ + RBO_FLAG_USE_DEACTIVATION = (1<<3), + /* rigidbody is deactivated at the beginning of simulation */ + RBO_FLAG_START_DEACTIVATED = (1<<4), + /* rigidbody is not dynamically simulated */ + RBO_FLAG_DISABLED = (1<<5), + /* collision margin is not embedded (only used by convex hull shapes for now) */ + RBO_FLAG_USE_MARGIN = (1<<6) +} eRigidBodyOb_Flag; + +/* RigidBody Collision Shape */ +typedef enum eRigidBody_Shape { + /* simple box (i.e. bounding box) */ + RB_SHAPE_BOX = 0, + /* sphere */ + RB_SHAPE_SPHERE, + /* rounded "pill" shape (i.e. calcium tablets) */ + RB_SHAPE_CAPSULE, + /* cylinder (i.e. pringles can) */ + RB_SHAPE_CYLINDER, + /* cone (i.e. party hat) */ + RB_SHAPE_CONE, + + /* convex hull (minimal shrinkwrap encompassing all verts) */ + RB_SHAPE_CONVEXH, + /* triangulated mesh */ + RB_SHAPE_TRIMESH, + + /* concave mesh approximated using primitives */ + //RB_SHAPE_COMPOUND, +} eRigidBody_Shape; + +/* ******************************** */ + +#endif /* __DNA_RIGIDBODY_TYPES_H__ */ + diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index b093239c714..b35323def29 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1170,6 +1170,9 @@ typedef struct Scene { ColorManagedViewSettings view_settings; ColorManagedDisplaySettings display_settings; ColorManagedColorspaceSettings sequencer_colorspace_settings; + + /* RigidBody simulation world+settings */ + struct RigidBodyWorld *rigidbody_world; } Scene; diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index e131cde8b27..31ff0ffa8fe 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -133,6 +133,7 @@ static const char *includefiles[] = { "DNA_tracking_types.h", "DNA_dynamicpaint_types.h", "DNA_mask_types.h", + "DNA_rigidbody_types.h", /* empty string to indicate end of includefiles */ "" @@ -1262,4 +1263,5 @@ int main(int argc, char **argv) #include "DNA_tracking_types.h" #include "DNA_dynamicpaint_types.h" #include "DNA_mask_types.h" +#include "DNA_rigidbody_types.h" /* end of list */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 6ce3ffa0461..e8c1a5d0642 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -428,6 +428,8 @@ extern StructRNA RNA_RenderLayer; extern StructRNA RNA_RenderPass; extern StructRNA RNA_RenderResult; extern StructRNA RNA_RenderSettings; +extern StructRNA RNA_RigidBodyWorld; +extern StructRNA RNA_RigidBodyObject; extern StructRNA RNA_RigidBodyJointConstraint; extern StructRNA RNA_SPHFluidSettings; extern StructRNA RNA_Scene; diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 75c8b2034b0..f0de36bbdfe 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -102,6 +102,9 @@ extern EnumPropertyItem object_type_items[]; extern EnumPropertyItem object_type_curve_items[]; +extern EnumPropertyItem rigidbody_ob_type_items[]; +extern EnumPropertyItem rigidbody_ob_shape_items[]; + extern EnumPropertyItem object_axis_items[]; extern EnumPropertyItem controller_type_items[]; diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript index aab08a3366e..df7d0f6f6de 100644 --- a/source/blender/makesrna/SConscript +++ b/source/blender/makesrna/SConscript @@ -38,6 +38,7 @@ incs += ' ../render/extern/include #/intern/cycles/blender' incs += ' ../nodes' incs += ' #/extern/glew/include' incs += ' #/intern/smoke/extern' +incs += ' ../rigidbody' incs += ' ../bmesh' diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 82c0757456d..83e7a19572d 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -70,6 +70,7 @@ set(DEFSRC rna_pose.c rna_property.c rna_render.c + rna_rigidbody.c rna_rna.c rna_scene.c rna_screen.c @@ -253,6 +254,7 @@ blender_include_dirs( ../../windowmanager ../../editors/include ../../render/extern/include + ../../rigidbody ../../../../intern/audaspace/intern ../../../../intern/cycles/blender ../../../../intern/guardedalloc diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 605fb18d5aa..41b6e3e5ca6 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3259,6 +3259,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_pose.c", "rna_pose_api.c", RNA_def_pose}, {"rna_property.c", NULL, RNA_def_gameproperty}, {"rna_render.c", NULL, RNA_def_render}, + {"rna_rigidbody.c", NULL, RNA_def_rigidbody}, {"rna_scene.c", "rna_scene_api.c", RNA_def_scene}, {"rna_screen.c", NULL, RNA_def_screen}, {"rna_sculpt_paint.c", NULL, RNA_def_sculpt_paint}, diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 6520f22fbf5..76947d856f8 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -164,6 +164,7 @@ void RNA_def_packedfile(struct BlenderRNA *brna); void RNA_def_particle(struct BlenderRNA *brna); void RNA_def_pose(struct BlenderRNA *brna); void RNA_def_render(struct BlenderRNA *brna); +void RNA_def_rigidbody(struct BlenderRNA *brna); void RNA_def_rna(struct BlenderRNA *brna); void RNA_def_scene(struct BlenderRNA *brna); void RNA_def_screen(struct BlenderRNA *brna); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 5105470a103..99cecb01140 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2428,6 +2428,12 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Particle Systems", "Particle systems emitted from the object"); rna_def_object_particle_systems(brna, prop); + + prop = RNA_def_property(srna, "rigid_body", PROP_POINTER, PROP_NONE); + 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"); + /* restrict */ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_VIEW); diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c new file mode 100644 index 00000000000..c7d6324b881 --- /dev/null +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -0,0 +1,499 @@ +/* + * ***** 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. + * + * Contributor(s): Blender Foundation 2013, Joshua Leung, Sergej Reich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file rna_rigidbody.c + * \ingroup rna + * \brief RNA property definitions for Rigid Body datatypes + */ + +#include <stdlib.h> +#include <string.h> + +#include "RNA_define.h" + +#include "rna_internal.h" + +#include "DNA_group_types.h" +#include "DNA_object_types.h" +#include "DNA_rigidbody_types.h" +#include "DNA_scene_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "WM_types.h" + +/* roles of objects in RigidBody Sims */ +EnumPropertyItem rigidbody_ob_type_items[] = { + {RBO_TYPE_ACTIVE, "ACTIVE", 0, "Active", "Object is directly controlled by simulation results"}, + {RBO_TYPE_PASSIVE, "PASSIVE", 0, "Passive", "Object is directly controlled by animation system"}, + {0, NULL, 0, NULL, NULL}}; + +/* collision shapes of objects in rigid body sim */ +EnumPropertyItem rigidbody_ob_shape_items[] = { + {RB_SHAPE_BOX, "BOX", ICON_MESH_CUBE, "Box", "Box-like shapes (i.e. cubes), including planes (i.e. ground planes)"}, + {RB_SHAPE_SPHERE, "SPHERE", ICON_MESH_UVSPHERE, "Sphere", ""}, + {RB_SHAPE_CAPSULE, "CAPSULE", ICON_OUTLINER_OB_META, "Capsule", ""}, + {RB_SHAPE_CYLINDER, "CYLINDER", ICON_MESH_CYLINDER, "Cylinder", ""}, + {RB_SHAPE_CONE, "CONE", ICON_MESH_CONE, "Cone", ""}, + {RB_SHAPE_CONVEXH, "CONVEX_HULL", ICON_MESH_ICOSPHERE, "Convex Hull", "A mesh-like surface encompassing (i.e. shrinkwrap over) all verts. Best results with fewer vertices"}, + {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}}; + + +#ifdef RNA_RUNTIME + +#include "RBI_api.h" + +#include "BKE_depsgraph.h" +#include "BKE_rigidbody.h" + +#define RB_FLAG_SET(dest, value, flag) { \ + if (value) \ + dest |= flag; \ + else \ + dest &= ~flag; \ +} + + +/* ******************************** */ + +static void rna_RigidBodyWorld_reset(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + RigidBodyWorld *rbw = (RigidBodyWorld *)ptr->data; + + BKE_rigidbody_cache_reset(rbw); +} + +static char *rna_RigidBodyWorld_path(PointerRNA *ptr) +{ + return BLI_sprintfN("rigidbody_world"); +} + +static void rna_RigidBodyWorld_num_solver_iterations_set(PointerRNA *ptr, int value) +{ + RigidBodyWorld *rbw = (RigidBodyWorld *)ptr->data; + + rbw->num_solver_iterations = value; + + if (rbw->physics_world) + RB_dworld_set_solver_iterations(rbw->physics_world, value); +} + +static void rna_RigidBodyWorld_split_impulse_set(PointerRNA *ptr, int value) +{ + RigidBodyWorld *rbw = (RigidBodyWorld *)ptr->data; + + RB_FLAG_SET(rbw->flag, value, RBW_FLAG_USE_SPLIT_IMPULSE); + + if (rbw->physics_world) + RB_dworld_set_split_impulse(rbw->physics_world, value); +} + +/* ******************************** */ + +static void rna_RigidBodyOb_reset(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + RigidBodyWorld *rbw = scene->rigidbody_world; + + BKE_rigidbody_cache_reset(rbw); +} + +static void rna_RigidBodyOb_shape_reset(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + RigidBodyWorld *rbw = scene->rigidbody_world; + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + BKE_rigidbody_cache_reset(rbw); + if (rbo->physics_shape) + rbo->flag |= RBO_FLAG_NEEDS_RESHAPE; +} + +static char *rna_RigidBodyOb_path(PointerRNA *ptr) +{ + /* NOTE: this hardcoded path should work as long as only Objects have this */ + return BLI_sprintfN("rigid_body"); +} + +static void rna_RigidBodyOb_type_set(PointerRNA *ptr, int value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + rbo->type = value; + rbo->flag |= RBO_FLAG_NEEDS_VALIDATE; + + /* do physics sim updates */ + if (rbo->physics_object) + RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); +} + +static void rna_RigidBodyOb_disabled_set(PointerRNA *ptr, int value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + RB_FLAG_SET(rbo->flag, !value, RBO_FLAG_DISABLED); + + /* update kinematic state if necessary - only needed for active bodies */ + if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) { + RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); + RB_body_set_kinematic_state(rbo->physics_object, !value); + rbo->flag |= RBO_FLAG_NEEDS_VALIDATE; + } +} + +static void rna_RigidBodyOb_shape_set(PointerRNA *ptr, int value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + Object *ob = (Object *)ptr->id.data; + + rbo->shape = value; + + /* force creation of new collision shape reflecting this */ + BKE_rigidbody_validate_sim_shape(ob, TRUE); + + /* now tell RB sim about it */ + if (rbo->physics_object && rbo->physics_shape) + RB_body_set_collision_shape(rbo->physics_object, rbo->physics_shape); +} + + +static void rna_RigidBodyOb_mass_set(PointerRNA *ptr, float value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + rbo->mass = value; + + /* only active bodies need mass update */ + if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) + RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); +} + +static void rna_RigidBodyOb_friction_set(PointerRNA *ptr, float value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + rbo->friction = value; + + if (rbo->physics_object) + RB_body_set_friction(rbo->physics_object, value); +} + +static void rna_RigidBodyOb_restitution_set(PointerRNA *ptr, float value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + rbo->restitution = value; + + if (rbo->physics_object) + RB_body_set_restitution(rbo->physics_object, value); +} + +static void rna_RigidBodyOb_collision_margin_set(PointerRNA *ptr, float value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + rbo->margin = value; + + if (rbo->physics_shape) + RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo)); +} + +static void rna_RigidBodyOb_kinematic_state_set(PointerRNA *ptr, int value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + RB_FLAG_SET(rbo->flag, value, RBO_FLAG_KINEMATIC); + + /* update kinematic state if necessary */ + if (rbo->physics_object) { + RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); + RB_body_set_kinematic_state(rbo->physics_object, value); + rbo->flag |= RBO_FLAG_NEEDS_VALIDATE; + } +} + +static void rna_RigidBodyOb_activation_state_set(PointerRNA *ptr, int value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + RB_FLAG_SET(rbo->flag, value, RBO_FLAG_USE_DEACTIVATION); + + /* update activation state if necessary - only active bodies can be deactivated */ + if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) + RB_body_set_activation_state(rbo->physics_object, value); +} + +static void rna_RigidBodyOb_linear_sleepThresh_set(PointerRNA *ptr, float value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + rbo->lin_sleep_thresh = value; + + /* only active bodies need sleep threshold update */ + if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) + RB_body_set_linear_sleep_thresh(rbo->physics_object, value); +} + +static void rna_RigidBodyOb_angular_sleepThresh_set(PointerRNA *ptr, float value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + rbo->ang_sleep_thresh = value; + + /* only active bodies need sleep threshold update */ + if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) + RB_body_set_angular_sleep_thresh(rbo->physics_object, value); +} + +static void rna_RigidBodyOb_linear_damping_set(PointerRNA *ptr, float value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + rbo->lin_damping = value; + + /* only active bodies need damping update */ + if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) + RB_body_set_linear_damping(rbo->physics_object, value); +} + +static void rna_RigidBodyOb_angular_damping_set(PointerRNA *ptr, float value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + rbo->ang_damping = value; + + /* only active bodies need damping update */ + if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) + RB_body_set_angular_damping(rbo->physics_object, value); +} + +#else + +static void rna_def_rigidbody_world(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "RigidBodyWorld", NULL); + RNA_def_struct_sdna(srna, "RigidBodyWorld"); + RNA_def_struct_ui_text(srna, "Rigid Body World", "Self-contained rigid body simulation environment and settings"); + RNA_def_struct_path_func(srna, "rna_RigidBodyWorld_path"); + + /* groups */ + prop = RNA_def_property(srna, "group", 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, "Group", "Group containing objects participating in this simulation"); + RNA_def_property_update(prop, NC_SCENE, "rna_RigidBodyWorld_reset"); + + /* booleans */ + prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", RBW_FLAG_MUTED); + RNA_def_property_ui_text(prop, "Enabled", "Simulation will be evaluated"); + RNA_def_property_update(prop, NC_SCENE, NULL); + + /* time scale */ + prop = RNA_def_property(srna, "time_scale", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "time_scale"); + RNA_def_property_range(prop, 0.0f, 100.0f); + RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Time Scale", "Changes the speed of the simulation"); + RNA_def_property_update(prop, NC_SCENE, "rna_RigidBodyWorld_reset"); + + /* timestep */ + prop = RNA_def_property(srna, "steps_per_second", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "steps_per_second"); + RNA_def_property_range(prop, 1, SHRT_MAX); + RNA_def_property_ui_range(prop, 60, 1000, 1, 0); + RNA_def_property_int_default(prop, 60); + RNA_def_property_ui_text(prop, "Steps Per Second", "Number of simulation steps taken per second (higher values are more accurate but slower)"); + RNA_def_property_update(prop, NC_SCENE, "rna_RigidBodyWorld_reset"); + + /* constraint solver iterations */ + 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, 10, 100, 1, 0); + RNA_def_property_int_default(prop, 10); + RNA_def_property_int_funcs(prop, NULL, "rna_RigidBodyWorld_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_SCENE, "rna_RigidBodyWorld_reset"); + + /* split impulse */ + prop = RNA_def_property(srna, "use_split_impulse", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBW_FLAG_USE_SPLIT_IMPULSE); + RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyWorld_split_impulse_set"); + RNA_def_property_ui_text(prop, "Split Impulse", "Reduces extra velocity that can build up when objects collide (lowers simulation stabilty a litte so use only when necessary)"); + RNA_def_property_update(prop, NC_SCENE, "rna_RigidBodyWorld_reset"); +} + +static void rna_def_rigidbody_object(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + + srna = RNA_def_struct(brna, "RigidBodyObject", NULL); + RNA_def_struct_sdna(srna, "RigidBodyOb"); + RNA_def_struct_ui_text(srna, "Rigid Body Object", "Settings for object participating in Rigid Body Simulation"); + RNA_def_struct_path_func(srna, "rna_RigidBodyOb_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_ob_type_items); + RNA_def_property_enum_funcs(prop, NULL, "rna_RigidBodyOb_type_set", NULL); + RNA_def_property_ui_text(prop, "Type", "Role of object in Rigid Body Simulations"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + /* booleans */ + prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", RBO_FLAG_DISABLED); + RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyOb_disabled_set"); + RNA_def_property_ui_text(prop, "Enabled", "Rigid Body actively participated in the simulation"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "collision_shape", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "shape"); + RNA_def_property_enum_items(prop, rigidbody_ob_shape_items); + RNA_def_property_enum_funcs(prop, NULL, "rna_RigidBodyOb_shape_set", NULL); + RNA_def_property_ui_text(prop, "Collision Shape", "Collision Shape of object in Rigid Body Simulations"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "kinematic", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_KINEMATIC); + RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyOb_kinematic_state_set"); + RNA_def_property_ui_text(prop, "Kinematic", "Allows rigid body to be controlled by the animation system"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + /* Physics Parameters */ + prop = RNA_def_property(srna, "mass", PROP_FLOAT, PROP_UNIT_MASS); + RNA_def_property_float_sdna(prop, NULL, "mass"); + RNA_def_property_range(prop, 0.001f, FLT_MAX); // range must always be positive (and non-zero) + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyOb_mass_set", NULL); + RNA_def_property_ui_text(prop, "Mass", "How much the object 'weighs' irrespective of gravity"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + /* Dynamics Parameters - Activation */ + // TODO: define and figure out how to implement these + + /* Dynamics Parameters - Deactivation */ + prop = RNA_def_property(srna, "use_deactivation", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_USE_DEACTIVATION); + RNA_def_property_boolean_default(prop, TRUE); + RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyOb_activation_state_set"); + RNA_def_property_ui_text(prop, "Enable Deactivation", "Enables deactivation of resting rigid bodies (increases performance and stability but can cause glitches)"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "start_deactivated", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_START_DEACTIVATED); + RNA_def_property_ui_text(prop, "Start Deactivated", "Deactivates rigid body at the start of the simulation"); + 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, "deactivate_linear_velocity", PROP_FLOAT, PROP_UNIT_VELOCITY); + RNA_def_property_float_sdna(prop, NULL, "lin_sleep_thresh"); + RNA_def_property_range(prop, FLT_MIN, FLT_MAX); // range must always be positive (and non-zero) + RNA_def_property_float_default(prop, 0.4f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyOb_linear_sleepThresh_set", NULL); + RNA_def_property_ui_text(prop, "Linear Velocity Deactivation Threshold", "Linear Velocity below which simulation stops simulating object"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "deactivate_angular_velocity", PROP_FLOAT, PROP_UNIT_VELOCITY); + RNA_def_property_float_sdna(prop, NULL, "ang_sleep_thresh"); + RNA_def_property_range(prop, FLT_MIN, FLT_MAX); // range must always be positive (and non-zero) + RNA_def_property_float_default(prop, 0.5f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyOb_angular_sleepThresh_set", NULL); + RNA_def_property_ui_text(prop, "Angular Velocity Deactivation Threshold", "Angular Velocity below which simulation stops simulating object"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + /* Dynamics Parameters - Damping Parameters */ + prop = RNA_def_property(srna, "linear_damping", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "lin_damping"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_default(prop, 0.04f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyOb_linear_damping_set", NULL); + RNA_def_property_ui_text(prop, "Linear Damping", "Amount of linear velocity that is lost over time"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "angular_damping", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "ang_damping"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_default(prop, 0.1f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyOb_angular_damping_set", NULL); + RNA_def_property_ui_text(prop, "Angular Damping", "Amount of angular velocity that is lost over time"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + /* Collision Parameters - Surface Parameters */ + prop = RNA_def_property(srna, "friction", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "friction"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 3); + RNA_def_property_float_default(prop, 0.5f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyOb_friction_set", NULL); + RNA_def_property_ui_text(prop, "Friction", "Resistance of object to movement"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "restitution", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "restitution"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 3); + RNA_def_property_float_default(prop, 0.0f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyOb_restitution_set", NULL); + RNA_def_property_ui_text(prop, "Restitution", "Tendency of object to bounce after colliding with another (0 = stays still, 1 = perfectly elastic)"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + + /* Collision Parameters - Sensitivity */ + prop = RNA_def_property(srna, "use_margin", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_USE_MARGIN); + RNA_def_property_boolean_default(prop, FALSE); + RNA_def_property_ui_text(prop, "Collision Margin", "Use custom collision margin (some shapes will have a visible gap around them)"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_shape_reset"); + + prop = RNA_def_property(srna, "collision_margin", PROP_FLOAT, PROP_UNIT_LENGTH); + RNA_def_property_float_sdna(prop, NULL, "margin"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 3); + RNA_def_property_float_default(prop, 0.04f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyOb_collision_margin_set", NULL); + RNA_def_property_ui_text(prop, "Collision Margin", "Threshold of distance near surface where collisions are still considered (best results when non-zero)"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_shape_reset"); + + prop = RNA_def_property(srna, "collision_groups", PROP_BOOLEAN, PROP_LAYER_MEMBER); + RNA_def_property_boolean_sdna(prop, NULL, "col_groups", 1); + RNA_def_property_array(prop, 20); + RNA_def_property_ui_text(prop, "Collison Groups", "Collision Groups Rigid Body belongs to"); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); +} + +void RNA_def_rigidbody(BlenderRNA *brna) +{ + rna_def_rigidbody_world(brna); + rna_def_rigidbody_object(brna); +} + + +#endif diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index bbacc4487c3..705ac09382d 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -35,6 +35,7 @@ #include "DNA_group_types.h" #include "DNA_modifier_types.h" #include "DNA_particle_types.h" +#include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" #include "DNA_userdef_types.h" #include "DNA_world_types.h" @@ -405,8 +406,7 @@ static void rna_Scene_object_unlink(Scene *scene, ReportList *reports, Object *o scene->basact = NULL; } - BLI_remlink(&scene->base, base); - MEM_freeN(base); + BKE_scene_base_remove(scene, base); ob->id.us--; @@ -4553,6 +4553,13 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_KEYINGSET, NULL); rna_def_scene_keying_sets_all(brna, prop); + /* Rigid Body Simulation */ + prop = RNA_def_property(srna, "rigidbody_world", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "rigidbody_world"); + RNA_def_property_struct_type(prop, "RigidBodyWorld"); + RNA_def_property_ui_text(prop, "Rigid Body World", ""); + RNA_def_property_update(prop, NC_SCENE, NULL); + /* Tool Settings */ prop = RNA_def_property(srna, "tool_settings", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); |