rigidbody: Add point cache support
authorSergej Reich <sergej.reich@googlemail.com>
Wed, 23 Jan 2013 05:56:34 +0000 (05:56 +0000)
committerSergej Reich <sergej.reich@googlemail.com>
Wed, 23 Jan 2013 05:56:34 +0000 (05:56 +0000)
Add read/write/interpolate functions.

In order to get rigid body point cache id from object it's now required to pass the
scene to BKE_ptcache_ids_from_object().

Rigid body cache is drawn in the orange color of the bullet logo.

12 files changed:
release/scripts/startup/bl_ui/space_time.py
source/blender/blenkernel/BKE_pointcache.h
source/blender/blenkernel/intern/pointcache.c
source/blender/blenkernel/intern/rigidbody.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/object/object_edit.c
source/blender/editors/space_time/space_time.c
source/blender/makesdna/DNA_rigidbody_types.h
source/blender/makesdna/DNA_space_types.h
source/blender/makesrna/intern/rna_rigidbody.c
source/blender/makesrna/intern/rna_space.c

index cb9e2444793ecc3b241f408e806a33844b6cdbe4..6af9f37723761eadafcf4491f25a642a1296e390 100644 (file)
@@ -152,6 +152,7 @@ class TIME_MT_cache(Menu):
         col.prop(st, "cache_cloth")
         col.prop(st, "cache_smoke")
         col.prop(st, "cache_dynamicpaint")
+        col.prop(st, "cache_rigidbody")
 
 
 class TIME_MT_frame(Menu):
index 7203400b267e17b18b1588f27adacab754003d4e..1cb50425c40fca6f757f4e03ddb13a15aa367a14 100644 (file)
@@ -67,6 +67,7 @@
 #define PTCACHE_TYPE_SMOKE_DOMAIN       3
 #define PTCACHE_TYPE_SMOKE_HIGHRES      4
 #define PTCACHE_TYPE_DYNAMICPAINT       5
+#define PTCACHE_TYPE_RIGIDBODY          6
 
 /* high bits reserved for flags that need to be stored in file */
 #define PTCACHE_TYPEFLAG_COMPRESS       (1 << 16)
@@ -91,6 +92,7 @@ struct PointCache;
 struct Scene;
 struct SmokeModifierData;
 struct SoftBody;
+struct RigidBodyWorld;
 
 /* temp structure for read/write */
 typedef struct PTCacheData {
@@ -260,6 +262,7 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct Par
 void BKE_ptcache_id_from_cloth(PTCacheID *pid, struct Object *ob, struct ClothModifierData *clmd);
 void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd);
 void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, struct Object *ob, struct DynamicPaintSurface *surface);
+void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct RigidBodyWorld *rbw);
 
 void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis);
 
index ac4b3099ba0933bc836752966dcb829b0ecf3523..afc552ae7f30af13e86f55535c61c8163befde22 100644 (file)
@@ -43,6 +43,7 @@
 #include "DNA_object_types.h"
 #include "DNA_object_force.h"
 #include "DNA_particle_types.h"
+#include "DNA_rigidbody_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_smoke_types.h"
 
@@ -72,6 +73,8 @@
 
 #include "BIK_api.h"
 
+#include "RBI_api.h"
+
 /* both in intern */
 #ifdef WITH_SMOKE
 #include "smoke_API.h"
@@ -867,6 +870,97 @@ static int ptcache_dynamicpaint_read(PTCacheFile *pf, void *dp_v)
        return 1;
 }
 
+/* Rigid Body functions */
+static int  ptcache_rigidbody_write(int index, void *rb_v, void **data, int UNUSED(cfra))
+{
+       RigidBodyWorld *rbw = rb_v;
+       Object *ob = NULL;
+       
+       if (rbw->objects)
+               ob = rbw->objects[index];
+       
+       if (ob && ob->rigidbody_object) {
+               RigidBodyOb *rbo = ob->rigidbody_object;
+               
+               if (rbo->type == RBO_TYPE_ACTIVE) {
+                       
+                       RB_body_get_position(rbo->physics_object, rbo->pos);
+                       RB_body_get_orientation(rbo->physics_object, rbo->orn);
+                       
+                       PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, rbo->pos);
+                       PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, rbo->orn);
+               }
+       }
+
+       return 1;
+}
+static void ptcache_rigidbody_read(int index, void *rb_v, void **data, float UNUSED(cfra), float *old_data)
+{
+       RigidBodyWorld *rbw = rb_v;
+       Object *ob = NULL;
+       
+       if (rbw->objects)
+               ob = rbw->objects[index];
+       
+       if (ob && ob->rigidbody_object) {
+               RigidBodyOb *rbo = ob->rigidbody_object;
+               
+               if (rbo->type == RBO_TYPE_ACTIVE) {
+                       
+                       if (old_data) {
+                               memcpy(rbo->pos, data, 3 * sizeof(float));
+                               memcpy(rbo->orn, data + 3, 4 * sizeof(float));
+                       }
+                       else {
+                               PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, rbo->pos);
+                               PTCACHE_DATA_TO(data, BPHYS_DATA_ROTATION, 0, rbo->orn);
+                       }
+               }
+       }
+}
+static void ptcache_rigidbody_interpolate(int index, void *rb_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
+{
+       RigidBodyWorld *rbw = rb_v;
+       Object *ob = NULL;
+       ParticleKey keys[4];
+       float dfra;
+       
+       if (rbw->objects)
+               ob = rbw->objects[index];
+       
+       if (ob && ob->rigidbody_object) {
+               RigidBodyOb *rbo = ob->rigidbody_object;
+               
+               if (rbo->type == RBO_TYPE_ACTIVE) {
+                       
+                       copy_v3_v3(keys[1].co, rbo->pos);
+                       copy_v3_v3(keys[1].rot, rbo->orn);
+                       
+                       if (old_data) {
+                               memcpy(keys[2].co, data, 3 * sizeof(float));
+                               memcpy(keys[2].rot, data + 3, 4 * sizeof(float));
+                       }
+                       else {
+                               BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2);
+                       }
+                       
+                       dfra = cfra2 - cfra1;
+               
+                       psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, keys, 1);
+                       interp_qt_qtqt(keys->rot, keys[1].rot, keys[2].rot, (cfra - cfra1) / dfra);
+                       
+                       copy_v3_v3(rbo->pos, keys->co);
+                       copy_v3_v3(rbo->orn, keys->rot);
+               }
+       }
+}
+static int ptcache_rigidbody_totpoint(void *rb_v, int UNUSED(cfra))
+{
+       RigidBodyWorld *rbw = rb_v;
+       
+       return rbw->numbodies;
+}
+
 /* Creating ID's */
 void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
 {
@@ -1072,6 +1166,42 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu
        pid->max_step = 1;
 }
 
+void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *rbw)
+{
+       
+       memset(pid, 0, sizeof(PTCacheID));
+       
+       pid->ob= ob;
+       pid->calldata= rbw;
+       pid->type= PTCACHE_TYPE_RIGIDBODY;
+       pid->cache= rbw->pointcache;
+       pid->cache_ptr= &rbw->pointcache;
+       pid->ptcaches= &rbw->ptcaches;
+       pid->totpoint= pid->totwrite= ptcache_rigidbody_totpoint;
+       
+       pid->write_point                        = ptcache_rigidbody_write;
+       pid->read_point                         = ptcache_rigidbody_read;
+       pid->interpolate_point          = ptcache_rigidbody_interpolate;
+       
+       pid->write_stream                       = NULL;
+       pid->read_stream                        = NULL;
+       
+       pid->write_extra_data           = NULL;
+       pid->read_extra_data            = NULL;
+       pid->interpolate_extra_data     = NULL;
+       
+       pid->write_header                       = ptcache_basic_header_write;
+       pid->read_header                        = ptcache_basic_header_read;
+       
+       pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_ROTATION);
+       pid->info_types= 0;
+       
+       pid->stack_index = pid->cache->index;
+       
+       pid->default_step = 1;
+       pid->max_step = 1;
+}
+
 void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis)
 {
        PTCacheID *pid;
@@ -1133,6 +1263,12 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup
                        }
                }
        }
+       
+       if (scene && ob->rigidbody_object && scene->rigidbody_world) {
+               pid = MEM_callocN(sizeof(PTCacheID), "PTCacheID");
+               BKE_ptcache_id_from_rigidbody(pid, ob, scene->rigidbody_world);
+               BLI_addtail(lb, pid);
+       }
 
        if (scene && (duplis-- > 0) && (ob->transflag & OB_DUPLI)) {
                ListBase *lb_dupli_ob;
@@ -2641,6 +2777,14 @@ int  BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
                }
        }
 
+       if (scene->rigidbody_world && ob->rigidbody_object) {
+               if (ob->rigidbody_object)
+                       ob->rigidbody_object->flag |= RBO_FLAG_NEEDS_RESHAPE;
+               BKE_ptcache_id_from_rigidbody(&pid, ob, scene->rigidbody_world);
+               /* only flag as outdated, resetting should happen on start frame */
+               pid.cache->flag |= PTCACHE_OUTDATED;
+       }
+
        if (ob->type == OB_ARMATURE)
                BIK_clear_cache(ob->pose);
 
index 90200fd6742299a120ef903bb04ad216934d7fce..17ced6fa54d7eba1464eabe567d6d53480c72bc8 100644 (file)
@@ -97,6 +97,10 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
        if (rbw->objects)
                free(rbw->objects);
 
+       /* free cache */
+       BKE_ptcache_free_list(&(rbw->ptcaches));
+       rbw->pointcache = NULL;
+
        /* free effector weights */
        if (rbw->effector_weights)
                MEM_freeN(rbw->effector_weights);
@@ -472,6 +476,9 @@ RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene)
        rbw->steps_per_second = 60; /* Bullet default (60 Hz) */
        rbw->num_solver_iterations = 10; /* 10 is bullet default */
 
+       rbw->pointcache = BKE_ptcache_add(&(rbw->ptcaches));
+       rbw->pointcache->step = 1;
+
        /* return this sim world */
        return rbw;
 }
@@ -749,7 +756,8 @@ void BKE_rigidbody_sync_transforms(Scene *scene, Object *ob, float ctime)
 
 void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
 {
-// RB_TODO implement this
+       if (rbw)
+               rbw->pointcache->flag |= PTCACHE_OUTDATED;
 }
 
 /* ------------------ */
index b0f1d3f37eddf513e5746bc183adb9f21a1b9bd8..edb033e80f87ad206115d5db888c37ec657a18d4 100644 (file)
@@ -5303,6 +5303,12 @@ static void direct_link_scene(FileData *fd, Scene *sce)
                rbw->effector_weights = newdataadr(fd, rbw->effector_weights);
                if (!rbw->effector_weights)
                        rbw->effector_weights = BKE_add_effector_weights(NULL);
+
+               /* link cache */
+               direct_link_pointcache_list(fd, &rbw->ptcaches, &rbw->pointcache, FALSE);
+               /* make sure simulation starts from the beginning after loading file */
+               if (rbw->pointcache)
+                       rbw->ltime = rbw->pointcache->startframe;
        }
 }
 
index da50a05a3d99a6a2a1be2a14ac6323b4a1969700..ebd752c0118612c54c5c0d14b602070f904d63b2 100644 (file)
@@ -2307,6 +2307,7 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
                if (sce->rigidbody_world) {
                        writestruct(wd, DATA, "RigidBodyWorld", 1, sce->rigidbody_world);
                        writestruct(wd, DATA, "EffectorWeights", 1, sce->rigidbody_world->effector_weights);
+                       write_pointcaches(wd, &(sce->rigidbody_world->ptcaches));
                }
                
                sce= sce->id.next;
index fcc3b5d012e9eb761384119f707522838196108e..5e5e38c3e43e1738d9fa55091195a6e6179e52b4 100644 (file)
@@ -376,7 +376,7 @@ void ED_object_exit_editmode(bContext *C, int flag)
                scene->obedit = NULL; // XXX for context
 
                /* flag object caches as outdated */
-               BKE_ptcache_ids_from_object(&pidlist, obedit, NULL, 0);
+               BKE_ptcache_ids_from_object(&pidlist, obedit, scene, 0);
                for (pid = pidlist.first; pid; pid = pid->next) {
                        if (pid->type != PTCACHE_TYPE_PARTICLES) /* particles don't need reset on geometry change */
                                pid->cache->flag |= PTCACHE_OUTDATED;
index 13c1938d77cc0b9cebb5de6363781580b8553a2a..e5bd9e62c74235812a301b1132fc898df76e2084 100644 (file)
@@ -92,7 +92,7 @@ static void time_draw_sfra_efra(Scene *scene, View2D *v2d)
 
 #define CACHE_DRAW_HEIGHT   3.0f
 
-static void time_draw_cache(SpaceTime *stime, Object *ob)
+static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
 {
        PTCacheID *pid;
        ListBase pidlist;
@@ -102,7 +102,7 @@ static void time_draw_cache(SpaceTime *stime, Object *ob)
        if (!(stime->cache_display & TIME_CACHE_DISPLAY) || (!ob))
                return;
 
-       BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
+       BKE_ptcache_ids_from_object(&pidlist, ob, scene, 0);
 
        /* iterate over pointcaches on the active object, 
         * add spacetimecache and vertex array for each */
@@ -128,6 +128,9 @@ static void time_draw_cache(SpaceTime *stime, Object *ob)
                        case PTCACHE_TYPE_DYNAMICPAINT:
                                if (!(stime->cache_display & TIME_CACHE_DYNAMICPAINT)) continue;
                                break;
+                       case PTCACHE_TYPE_RIGIDBODY:
+                               if (!(stime->cache_display & TIME_CACHE_RIGIDBODY)) continue;
+                               break;
                }
 
                if (pid->cache->cached_frames == NULL)
@@ -193,6 +196,10 @@ static void time_draw_cache(SpaceTime *stime, Object *ob)
                                col[0] = 1.0;   col[1] = 0.1;   col[2] = 0.75;
                                col[3] = 0.1;
                                break;
+                       case PTCACHE_TYPE_RIGIDBODY:
+                               col[0] = 1.0;   col[1] = 0.6;   col[2] = 0.0;
+                               col[3] = 0.1;
+                               break;
                        default:
                                BLI_assert(0);
                                col[0] = 1.0;   col[1] = 0.0;   col[2] = 1.0;
@@ -499,7 +506,7 @@ static void time_main_area_draw(const bContext *C, ARegion *ar)
        draw_markers_time(C, 0);
        
        /* caches */
-       time_draw_cache(stime, obact);
+       time_draw_cache(stime, obact, scene);
        
        /* reset view matrix */
        UI_view2d_view_restore(C);
@@ -648,6 +655,7 @@ static void time_init(wmWindowManager *UNUSED(wm), ScrArea *sa)
        stime->cache_display |= TIME_CACHE_DISPLAY;
        stime->cache_display |= (TIME_CACHE_SOFTBODY | TIME_CACHE_PARTICLES);
        stime->cache_display |= (TIME_CACHE_CLOTH | TIME_CACHE_SMOKE | TIME_CACHE_DYNAMICPAINT);
+       stime->cache_display |= TIME_CACHE_RIGIDBODY;
 }
 
 static SpaceLink *time_duplicate(SpaceLink *sl)
index 43c2cdb227a958b0318d5277750ff35d8f02a80c..e08162fedd633f249d003c13c5b54e9efd63455d 100644 (file)
@@ -57,6 +57,8 @@ typedef struct RigidBodyWorld {
        float ltime;                            /* last frame world was evaluated for (internal) */
        
        /* cache */
+       struct PointCache *pointcache;
+       struct ListBase ptcaches;
        int numbodies;              /* number of objects in rigid body group */
        
        short steps_per_second;         /* number of simulation steps thaken per second */
index ae845cb5aa3d86405116c776643c7b9118962b3b..da9fdc776b5b17362c4cc3acd49040236075ca73 100644 (file)
@@ -447,6 +447,7 @@ typedef enum eTimeline_Cache_Flag {
        TIME_CACHE_CLOTH         = (1 << 3),
        TIME_CACHE_SMOKE         = (1 << 4),
        TIME_CACHE_DYNAMICPAINT  = (1 << 5),
+       TIME_CACHE_RIGIDBODY     = (1 << 6),
 } eTimeline_Cache_Flag;
 
 
index cd8b63cd0deb3ea772ec63ae92e0462f346e0171..1e0e250ac664398b000d7cd0afb704ce6caff3ce 100644 (file)
@@ -346,6 +346,12 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
        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");
 
+       /* cache */
+       prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
+       RNA_def_property_flag(prop, PROP_NEVER_NULL);
+       RNA_def_property_pointer_sdna(prop, NULL, "pointcache");
+       RNA_def_property_ui_text(prop, "Point Cache", "");
+
        /* effector weights */
        prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
        RNA_def_property_struct_type(prop, "EffectorWeights");
index 5d009a627e60b94f56b37917c6df8025327074b1..f7e9899421eb19616ecc2fa847ba20fd7c0c4cb5 100644 (file)
@@ -2760,6 +2760,11 @@ static void rna_def_space_time(BlenderRNA *brna)
        RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_DYNAMICPAINT);
        RNA_def_property_ui_text(prop, "Dynamic Paint", "Show the active object's Dynamic Paint cache");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
+       
+       prop = RNA_def_property(srna, "cache_rigidbody", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_RIGIDBODY);
+       RNA_def_property_ui_text(prop, "Rigid Body", "Show the active object's Rigid Body cache");
+       RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
 }
 
 static void rna_def_console_line(BlenderRNA *brna)