From bdb86d7c6765724d297e7aa97dec4c0cc7d2bae9 Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Sat, 2 Apr 2005 13:57:23 +0000 Subject: Integration stage of Softbody project User level notes are in Wiki here; http://wiki.blender.org/bin/view.pl/Blenderdev/Softbodies And will be added in blender3d.org CMS later. Tech level notes are still pending, but here's the most relevant ones; - made ob->soft struct SoftBody to hold all settings, and read/save in files - added (temporal!) conversion for the old settings. So: read old files with softbody experiments now, and save over! - cleaned API calls for softbody, which are only 5 of them now: sbNew() sbFree() sbObjectStep() (animation steps) sbObjectToSoftbody() (full re-initialize data) sbObjectReset() (only reset motion) - API calls accepts time in frames now, within softbody.c it converts Further, internally code was cleaned some (missing tabs etc). Also tried to keep a well defined structure with hints how to add support for more objects. Can write notes about that... --- source/blender/blenkernel/BKE_softbody.h | 30 +- source/blender/blenkernel/intern/deform.c | 12 +- source/blender/blenkernel/intern/lattice.c | 2 +- source/blender/blenkernel/intern/object.c | 2 +- source/blender/blenkernel/intern/softbody.c | 807 ++++++++++++++------------- source/blender/blenloader/intern/readfile.c | 30 +- source/blender/blenloader/intern/writefile.c | 1 + source/blender/makesdna/DNA_object_types.h | 40 +- source/blender/src/buttons_object.c | 91 ++- source/blender/src/editipo.c | 2 - source/blender/src/editobject.c | 11 +- source/blender/src/header_view3d.c | 20 +- source/blender/src/usiblender.c | 5 +- 13 files changed, 558 insertions(+), 495 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h index 24abff44a2b..09be644c9e7 100644 --- a/source/blender/blenkernel/BKE_softbody.h +++ b/source/blender/blenkernel/BKE_softbody.h @@ -46,29 +46,23 @@ typedef struct BodySpring { float len, strength; } BodySpring; -typedef struct SoftBody { - int totpoint, totspring; - - BodyPoint *bpoint; - BodySpring *bspring; - - float ctime; // last time calculated -} SoftBody; +struct Object; +struct SoftBody; -/* temporal data, nothing saved in file */ -extern void free_softbody(SoftBody *sb); +/* allocates and initializes general main data */ +extern struct SoftBody *sbNew(void); -/* makes totally fresh start situation */ -extern void object_to_softbody(Object *ob,float ctime); +/* frees internal data and softbody itself */ +extern void sbFree(struct SoftBody *sb); -/* copy original (but new) situation in softbody, as result of matrices or deform */ -void object_update_softbody(Object *ob); +/* go one step in simulation, copy result in displist vertices */ +extern void sbObjectStep(struct Object *ob, float framnr); -/* copies softbody result back to object (in displist) */ -extern void softbody_to_object(Object *ob); +/* makes totally fresh start situation, resets time */ +extern void sbObjectToSoftbody(struct Object *ob); -/* go one step in simulation */ -extern void object_softbody_step(Object *ob, float ctime); +/* resets all motion and time */ +extern void sbObjectReset(struct Object *ob); #endif diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index fbf72fb71b2..d1c156380e8 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -264,19 +264,17 @@ int mesh_modifier(Object *ob, char mode) if(ob->effect.first) done |= object_wave(ob); - if((ob->softflag & 0x01) && !(ob->softflag & 0x08)) { - float ctime= bsystem_time(ob, NULL, (float)G.scene->r.cfra, 0.0); + if((ob->softflag & OB_SB_ENABLE) && !(ob->softflag & OB_SB_POSTDEF)) { done= 1; - object_softbody_step(ob, ctime); + sbObjectStep(ob, (float)G.scene->r.cfra); } - /* deform: input mesh, output ob dl_verts. is used by subsurf (output should be in mesh ton!) */ + /* object_deform: output for mesh is in mesh->mvert */ done |= object_deform(ob); - if((ob->softflag & 0x01) && (ob->softflag & 0x08)) { - float ctime= bsystem_time(ob, NULL, (float)G.scene->r.cfra, 0.0); + if((ob->softflag & OB_SB_ENABLE) && (ob->softflag & OB_SB_POSTDEF)) { done= 1; - object_softbody_step(ob, ctime); + sbObjectStep(ob, (float)G.scene->r.cfra); } /* put deformed vertices in dl->verts, optional subsurf will replace that */ diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 5efbcd832b0..4d6f0942f91 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -507,7 +507,7 @@ static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *c } - +/* Mesh now applies on mesh itself, others do displist */ static int _object_deform(Object *ob, int applyflag) { Mesh *me; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 9285ed785a9..4342e5b3c8d 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -222,7 +222,7 @@ void free_object(Object *ob) BPY_free_scriptlink(&ob->scriptlink); if(ob->pd) MEM_freeN(ob->pd); - if(ob->soft) free_softbody(ob->soft); + if(ob->soft) sbFree(ob->soft); } void unlink_object(Object *ob) diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index bfc58070974..601b7e45afd 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -34,22 +34,18 @@ /* ****** variables on the UI for now -typedef struct Object { -..... - float formfactor, softtime; softtime = #euler integrations steps per frame -..... - float sb_goalspring; softbody goal springs - float sb_goalfrict; softbody goal springs friction - float sb_inspring; softbody inner springs - float sb_infrict; softbody inner springs friction - float sb_nodemass; softbody mass of *vertex* - float sb_grav; softbody amount of gravitaion to apply - float sb_mingoal; quick limits for goal - float sb_maxgoal; - float sb_mediafrict; friction to env - float sb_pad1; free - - + + float mediafrict; friction to env + float nodemass; softbody mass of *vertex* + float grav; softbody amount of gravitaion to apply + + float goalspring; softbody goal springs + float goalfrict; softbody goal springs friction + float mingoal; quick limits for goal + float maxgoal; + + float inspring; softbody inner springs + float infrict; softbody inner springs friction ***** */ @@ -62,7 +58,6 @@ typedef struct Object { #include "MEM_guardedalloc.h" /* types */ -#include "DNA_ika_types.h" #include "DNA_object_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -71,10 +66,11 @@ typedef struct Object { #include "BLI_blenlib.h" #include "BLI_arithb.h" +#include "BKE_displist.h" #include "BKE_global.h" -#include "BKE_utildefines.h" +#include "BKE_object.h" #include "BKE_softbody.h" -#include "BKE_displist.h" +#include "BKE_utildefines.h" #include "BIF_editdeform.h" @@ -93,30 +89,32 @@ float steptime = 1.0f/25.0f; // translate framerate to *real* time float rescale_grav_to_framerate = 1.0f; // since unit of g is [m/sec^2] we need translation from frames to physics time float rescale_friction_to_framerate = 1.0f; // since unit of drag is [kg/sec] we need translation from frames to physics time -short SB_ENABLE = 0; // quick hack to switch sb integration in 3d header - /* local prototypes */ -void softbody_scale_time(float steptime); -int get_scalar_from_named_vertexgroup(Object *ob, char *name, int vertID, float *target); +static void softbody_scale_time(float steptime); +static int get_scalar_from_named_vertexgroup(Object *ob, char *name, int vertID, float *target); +static void free_softbody_intern(SoftBody *sb); -void softbody_scale_time(float steptime) +static void softbody_scale_time(float steptime) { rescale_grav_to_framerate = steptime*steptime; rescale_friction_to_framerate = steptime; } -static int count_quads( Mesh *me) +static int count_mesh_quads(Mesh *me) { int a,result = 0; MFace *mface= me->mface; - if(mface ) { - for(a=me->totface; a>0; a--, mface++) {if(mface->v4) result++;} + + if(mface) { + for(a=me->totface; a>0; a--, mface++) { + if(mface->v4) result++; + } } return result; } -static void add_quad_diag_springs(Object *ob) +static void add_mesh_quad_diag_springs(Object *ob) { Mesh *me= ob->data; MFace *mface= me->mface; @@ -125,22 +123,23 @@ static void add_quad_diag_springs(Object *ob) int a ; if (ob->soft){ - int nofquads; - nofquads = count_quads(me); + int nofquads; + + nofquads = count_mesh_quads(me); if (nofquads) { /* resize spring-array to hold additional quad springs */ bs_new= MEM_callocN( (ob->soft->totspring + nofquads *2 )*sizeof(BodySpring), "bodyspring"); memcpy(bs_new,ob->soft->bspring,(ob->soft->totspring )*sizeof(BodySpring)); MEM_freeN(ob->soft->bspring); /* do this before reassigning the pointer or have a 1st class memory leak */ - ob->soft->bspring = bs_new; + ob->soft->bspring = bs_new; + /* fill the tail */ a = 0; bs = bs_new+ob->soft->totspring; bp= ob->soft->bpoint; if(mface ) { for(a=me->totface; a>0; a--, mface++) { - if(mface->v4) - { + if(mface->v4) { bs->v1= mface->v1; bs->v2= mface->v3; bs->strength= 1.0; @@ -158,15 +157,15 @@ static void add_quad_diag_springs(Object *ob) /* now we can announce new springs */ ob->soft->totspring += nofquads *2; - } } } -static void add_bp_springlist(BodyPoint *bp,int springID) +static void add_bp_springlist(BodyPoint *bp,int springID) { int *newlist; + if (bp->springs == NULL) { bp->springs = MEM_callocN( sizeof(int), "bpsprings"); bp->springs[0] = springID; @@ -185,14 +184,15 @@ static void add_bp_springlist(BodyPoint *bp,int springID) /* do this once when sb is build it is O(N^2) so scanning for springs every iteration is too expensive */ -static void build_bps_springlist(Object *ob) +static void build_bps_springlist(Object *ob) { SoftBody *sb= ob->soft; // is supposed to be there BodyPoint *bp; BodySpring *bs; - int a,b; - if (!sb) return; // paranoya check + + if (sb==NULL) return; // paranoya check + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { /* scan for attached inner springs */ for(b=sb->totspring, bs= sb->bspring; b>0; b--, bs++) { @@ -203,18 +203,22 @@ static void build_bps_springlist(Object *ob) add_bp_springlist(bp,sb->totspring -b); } }//for springs - if (bp->nofsprings) printf(" node %d has %d spring links\n",a,bp->nofsprings); + // if (bp->nofsprings) printf(" node %d has %d spring links\n",a,bp->nofsprings); }//for bp } - -static SoftBody *new_softbody(int totpoint, int totspring) +/* creates new softbody if didn't exist yet, makes new points and springs arrays */ +/* called in mesh_to_softbody */ +static void renew_softbody(Object *ob, int totpoint, int totspring) { - SoftBody *sb= NULL; + SoftBody *sb; + if(ob->soft==NULL) ob->soft= sbNew(); + else free_softbody_intern(ob->soft); + sb= ob->soft; + if(totpoint) { - sb= MEM_callocN(sizeof(SoftBody), "softbody"); sb->totpoint= totpoint; sb->totspring= totspring; @@ -222,14 +226,15 @@ static SoftBody *new_softbody(int totpoint, int totspring) if(totspring) sb->bspring= MEM_mallocN( totspring*sizeof(BodySpring), "bodyspring"); } - return sb; } -void free_softbody(SoftBody *sb) +/* only frees internal data */ +static void free_softbody_intern(SoftBody *sb) { if(sb) { int a; BodyPoint *bp; + if(sb->bpoint){ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { /* free spring list */ @@ -239,10 +244,16 @@ void free_softbody(SoftBody *sb) } MEM_freeN(sb->bpoint); } + if(sb->bspring) MEM_freeN(sb->bspring); - MEM_freeN(sb); + + sb->totpoint= sb->totspring= 0; + sb->bpoint= NULL; + sb->bspring= NULL; } } + + /* ************ dynamics ********** */ /* aye this belongs to arith.c */ @@ -258,17 +269,18 @@ static void softbody_calc_forces(Object *ob, float dtime) { SoftBody *sb= ob->soft; // is supposed to be there BodyPoint *bp; - float iks,ks,kd,gravity,actspringlen,forcefactor,sd[3]; - int a,b; BodyPoint *bproot; BodySpring *bs; + float iks, ks, kd, gravity, actspringlen, forcefactor, sd[3]; + int a, b; + /* clear forces */ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { bp->force[0]= bp->force[1]= bp->force[2]= 0.0; } - gravity = ob->sb_nodemass * ob->sb_grav * rescale_grav_to_framerate; - iks = 1.0f/(1.0f-ob->sb_inspring)-1.0f ;/* inner spring constants function */ + gravity = sb->nodemass * sb->grav * rescale_grav_to_framerate; + iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ bproot= sb->bpoint; /* need this for proper spring addressing */ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { @@ -278,34 +290,36 @@ static void softbody_calc_forces(Object *ob, float dtime) float absvel =0, projvel= 0; /* do goal stuff */ - /* true elastic goal */ - VecSubf(auxvect,bp->origT,bp->pos); - ks = 1.0f/(1.0f- bp->goal*ob->sb_goalspring)-1.0f ; - bp->force[0]= ks*(auxvect[0]); - bp->force[1]= ks*(auxvect[1]); - bp->force[2]= ks*(auxvect[2]); - /* calulate damping forces generated by goals*/ - VecSubf(velgoal,bp->origS, bp->origE); - kd = ob->sb_goalfrict * rescale_friction_to_framerate ; - - if (dtime > 0.0 ) { // make sure friction does not become rocket motor on time reversal - bp->force[0]-= kd * (velgoal[0] + bp->vec[0]); - bp->force[1]-= kd * (velgoal[1] + bp->vec[1]); - bp->force[2]-= kd * (velgoal[2] + bp->vec[2]); - } - else { - bp->force[0]-= kd * (velgoal[0] - bp->vec[0]); - bp->force[1]-= kd * (velgoal[1] - bp->vec[1]); - bp->force[2]-= kd * (velgoal[2] - bp->vec[2]); + if(ob->softflag & OB_SB_GOAL) { + /* true elastic goal */ + VecSubf(auxvect,bp->origT,bp->pos); + ks = 1.0f/(1.0f- bp->goal*sb->goalspring)-1.0f ; + bp->force[0]= ks*(auxvect[0]); + bp->force[1]= ks*(auxvect[1]); + bp->force[2]= ks*(auxvect[2]); + /* calulate damping forces generated by goals*/ + VecSubf(velgoal,bp->origS, bp->origE); + kd = sb->goalfrict * rescale_friction_to_framerate ; + + if (dtime > 0.0 ) { // make sure friction does not become rocket motor on time reversal + bp->force[0]-= kd * (velgoal[0] + bp->vec[0]); + bp->force[1]-= kd * (velgoal[1] + bp->vec[1]); + bp->force[2]-= kd * (velgoal[2] + bp->vec[2]); + } + else { + bp->force[0]-= kd * (velgoal[0] - bp->vec[0]); + bp->force[1]-= kd * (velgoal[1] - bp->vec[1]); + bp->force[2]-= kd * (velgoal[2] - bp->vec[2]); + } } /* done goal stuff */ /* gravitation */ - bp->force[2]-= gravity*ob->sb_nodemass; /* individual mass of node here */ + bp->force[2]-= gravity*sb->nodemass; /* individual mass of node here */ /* friction in media */ - kd= ob->sb_mediafrict* rescale_friction_to_framerate; + kd= sb->mediafrict* rescale_friction_to_framerate; /* assume it to be proportional to actual velocity */ bp->force[0]-= bp->vec[0]*kd; bp->force[1]-= bp->vec[1]*kd; @@ -326,85 +340,87 @@ static void softbody_calc_forces(Object *ob, float dtime) hrms .. may be a rough one could be used as well .. let's see */ - if (1){ /* big mesh optimization */ - /* run over attached inner spring list */ - if (sb->bspring){ // spring list exists at all ? - for(b=bp->nofsprings;b>0;b--){ - bs = sb->bspring + bp->springs[b-1]; + if(ob->softflag & OB_SB_EDGES) { + if (1){ /* big mesh optimization */ + /* run over attached inner spring list */ + if (sb->bspring){ // spring list exists at all ? + for(b=bp->nofsprings;b>0;b--){ + bs = sb->bspring + bp->springs[b-1]; + if (( (sb->totpoint-a) == bs->v1) ){ + actspringlen= VecLenf( (bproot+bs->v2)->pos, bp->pos); + VecSubf(sd,(bproot+bs->v2)->pos, bp->pos); + Normalise(sd); + + // friction stuff V1 + VecSubf(velgoal,bp->vec,(bproot+bs->v2)->vec); + kd = sb->infrict * rescale_friction_to_framerate ; + absvel = Normalise(velgoal); + projvel = ABS(Inpf(sd,velgoal)); + kd *= absvel * projvel; + Vec3PlusStVec(bp->force,-kd,velgoal); + + if(bs->len > 0.0) /* check for degenerated springs */ + forcefactor = (bs->len - actspringlen)/bs->len * iks; + else + forcefactor = actspringlen * iks; + + Vec3PlusStVec(bp->force,-forcefactor,sd); + + } + + if (( (sb->totpoint-a) == bs->v2) ){ + actspringlen= VecLenf( (bproot+bs->v1)->pos, bp->pos); + VecSubf(sd,bp->pos,(bproot+bs->v1)->pos); + Normalise(sd); + + // friction stuff V2 + VecSubf(velgoal,bp->vec,(bproot+bs->v1)->vec); + kd = sb->infrict * rescale_friction_to_framerate ; + absvel = Normalise(velgoal); + projvel = ABS(Inpf(sd,velgoal)); + kd *= absvel * projvel; + Vec3PlusStVec(bp->force,-kd,velgoal); + + if(bs->len > 0.0) + forcefactor = (bs->len - actspringlen)/bs->len * iks; + else + forcefactor = actspringlen * iks; + Vec3PlusStVec(bp->force,+forcefactor,sd); + } + } + } //if spring list exists at all ? + } + else{ // this branch is not completly uptaded for friction stuff + /* scan for attached inner springs makes it a O(N^2) thing = bad !*/ + /* obsolete .. but if someone wants to try the effect :) */ + for(b=sb->totspring, bs= sb->bspring; b>0; b--, bs++) { if (( (sb->totpoint-a) == bs->v1) ){ actspringlen= VecLenf( (bproot+bs->v2)->pos, bp->pos); VecSubf(sd,(bproot+bs->v2)->pos, bp->pos); Normalise(sd); - // friction stuff V1 - VecSubf(velgoal,bp->vec,(bproot+bs->v2)->vec); - kd = ob->sb_infrict * rescale_friction_to_framerate ; - absvel = Normalise(velgoal); - projvel = ABS(Inpf(sd,velgoal)); - kd *= absvel * projvel; - Vec3PlusStVec(bp->force,-kd,velgoal); - + if(bs->len > 0.0) /* check for degenerated springs */ forcefactor = (bs->len - actspringlen)/bs->len * iks; else forcefactor = actspringlen * iks; - Vec3PlusStVec(bp->force,-forcefactor,sd); - } if (( (sb->totpoint-a) == bs->v2) ){ actspringlen= VecLenf( (bproot+bs->v1)->pos, bp->pos); VecSubf(sd,bp->pos,(bproot+bs->v1)->pos); Normalise(sd); - - // friction stuff V2 - VecSubf(velgoal,bp->vec,(bproot+bs->v1)->vec); - kd = ob->sb_infrict * rescale_friction_to_framerate ; - absvel = Normalise(velgoal); - projvel = ABS(Inpf(sd,velgoal)); - kd *= absvel * projvel; - Vec3PlusStVec(bp->force,-kd,velgoal); if(bs->len > 0.0) forcefactor = (bs->len - actspringlen)/bs->len * iks; else forcefactor = actspringlen * iks; - Vec3PlusStVec(bp->force,+forcefactor,sd); + Vec3PlusStVec(bp->force,+forcefactor,sd); } - } - } //if spring list exists at all ? - } - else{ // this branch is not completly uptaded for friction stuff - /* scan for attached inner springs makes it a O(N^2) thing = bad !*/ - /* obsolete .. but if someone wants to try the effect :) */ - for(b=sb->totspring, bs= sb->bspring; b>0; b--, bs++) { - if (( (sb->totpoint-a) == bs->v1) ){ - actspringlen= VecLenf( (bproot+bs->v2)->pos, bp->pos); - VecSubf(sd,(bproot+bs->v2)->pos, bp->pos); - Normalise(sd); - - - if(bs->len > 0.0) /* check for degenerated springs */ - forcefactor = (bs->len - actspringlen)/bs->len * iks; - else - forcefactor = actspringlen * iks; - Vec3PlusStVec(bp->force,-forcefactor,sd); - } - - if (( (sb->totpoint-a) == bs->v2) ){ - actspringlen= VecLenf( (bproot+bs->v1)->pos, bp->pos); - VecSubf(sd,bp->pos,(bproot+bs->v1)->pos); - Normalise(sd); - - if(bs->len > 0.0) - forcefactor = (bs->len - actspringlen)/bs->len * iks; - else - forcefactor = actspringlen * iks; - Vec3PlusStVec(bp->force,+forcefactor,sd); - } - }// no snap - }//for + }// no snap + }//for + }// if use edges } } } @@ -417,11 +433,11 @@ static void softbody_apply_forces(Object *ob, float dtime, int mode, float *err) SoftBody *sb= ob->soft; // is supposed to be there BodyPoint *bp; float dx[3],dv[3]; - int a; float timeovermass; float maxerr = 0.0; + int a; - if (ob->sb_nodemass > 0.09999f) timeovermass = dtime/ob->sb_nodemass; + if (sb->nodemass > 0.09999f) timeovermass = dtime/sb->nodemass; else timeovermass = dtime/0.09999f; for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { @@ -436,8 +452,8 @@ static void softbody_apply_forces(Object *ob, float dtime, int mode, float *err) /* some nasty if's to have heun in here too */ VECCOPY(dv,bp->force); if (mode == 1){ - VECCOPY(bp->prevvec,bp->vec); - VECCOPY(bp->prevdv ,dv); + VECCOPY(bp->prevvec, bp->vec); + VECCOPY(bp->prevdv, dv); } if (mode ==2){ /* be optimistic and execute step */ @@ -488,41 +504,14 @@ static void softbody_restore_prev_step(Object *ob) { SoftBody *sb= ob->soft; // is supposed to be there BodyPoint *bp; - int a; - for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { - VECCOPY(bp->vec,bp->prevvec); - VECCOPY(bp->pos,bp->prevpos); - } -} - - -/* unused */ -#if 0 -static void softbody_apply_goal(Object *ob, float dtime) -{ - - SoftBody *sb= ob->soft; // is supposed to be there - BodyPoint *bp; - float vec[3], ks; int a; for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { - ks= bp->goal*dtime; - // this is hackish, screws up physics but stabilizes - vec[0]= ks*(bp->origT[0]-bp->pos[0]); - vec[1]= ks*(bp->origT[1]-bp->pos[1]); - vec[2]= ks*(bp->origT[2]-bp->pos[2]); - - VECADD(bp->pos, bp->pos, vec); - - ks= 1.0f-ks; - bp->vec[0]*= ks; - bp->vec[1]*= ks; - bp->vec[2]*= ks; - + VECCOPY(bp->vec, bp->prevvec); + VECCOPY(bp->pos, bp->prevpos); } } -#endif + static void softbody_apply_goalsnap(Object *ob) { @@ -538,6 +527,8 @@ static void softbody_apply_goalsnap(Object *ob) } } +/* unused */ +#if 0 static void softbody_force_goal(Object *ob) { SoftBody *sb= ob->soft; // is supposed to be there @@ -551,44 +542,67 @@ static void softbody_force_goal(Object *ob) bp->vec[2] = bp->origE[2] - bp->origS[2]; } } +#endif +/* expects full initialized softbody */ static void interpolate_exciter(Object *ob, int timescale, int time) { - Mesh *me= ob->data; - //MEdge *medge= me->medge; - int a; + SoftBody *sb= ob->soft; BodyPoint *bp; float f; + int a; + + // note: i removed Mesh usage here, softbody should remain generic! (ton) - if(ob->soft) { - f = (float)time/(float)timescale; - bp= ob->soft->bpoint; - for(a=0; atotvert; a++, bp++) { - bp->origT[0] = bp->origS[0] + f*(bp->origE[0] - bp->origS[0]); - bp->origT[1] = bp->origS[1] + f*(bp->origE[1] - bp->origS[1]); - bp->origT[2] = bp->origS[2] + f*(bp->origE[2] - bp->origS[2]); - if (bp->goal >= SOFTGOALSNAP){ - bp->vec[0] = bp->origE[0] - bp->origS[0]; - bp->vec[1] = bp->origE[1] - bp->origS[1]; - bp->vec[2] = bp->origE[2] - bp->origS[2]; - } + f = (float)time/(float)timescale; + + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + bp->origT[0] = bp->origS[0] + f*(bp->origE[0] - bp->origS[0]); + bp->origT[1] = bp->origS[1] + f*(bp->origE[1] - bp->origS[1]); + bp->origT[2] = bp->origS[2] + f*(bp->origE[2] - bp->origS[2]); + if (bp->goal >= SOFTGOALSNAP){ + bp->vec[0] = bp->origE[0] - bp->origS[0]; + bp->vec[1] = bp->origE[1] - bp->origS[1]; + bp->vec[2] = bp->origE[2] - bp->origS[2]; } + } + + if(ob->softflag & OB_SB_EDGES) { /* hrms .. do springs alter their lenght ? - if(medge) { bs= ob->soft->bspring; bp= ob->soft->bpoint; - for(a=0; (atotedge && a < ob->soft->totspring ); a++, medge++, bs++) { - bs->len= VecLenf( (bp+bs->v1)->origT, (bp+bs->v2)->origT); - } + for(a=0; (atotedge && a < ob->soft->totspring ); a++, bs++) { + bs->len= VecLenf( (bp+bs->v1)->origT, (bp+bs->v2)->origT); } */ - } + } } /* ************ convertors ********** */ +/* for each object type we need; + - xxxx_to_softbody(Object *ob) : a full (new) copy + - xxxx_update_softbody(Object *ob) : update refreshes current positions + - softbody_to_xxxx(Object *ob) : after simulation, copy vertex locations back +*/ + +static int object_has_edges(Object *ob) +{ + if(ob->type==OB_MESH) { + Mesh *me= ob->data; + if(me->medge) return 1; + } + else if(ob->type==OB_LATTICE) { + ; + } + + return 0; +} + + /* copy original (new) situation in softbody, as result of matrices or deform */ +/* is assumed to enter function with ob->soft, but can be without points */ static void mesh_update_softbody(Object *ob) { Mesh *me= ob->data; @@ -596,7 +610,11 @@ static void mesh_update_softbody(Object *ob) /* MEdge *medge= me->medge; */ /*unused*/ BodyPoint *bp; int a; - if(ob->soft) { + + /* possible after a file read... */ + if(ob->soft->totpoint!=me->totvert) sbObjectToSoftbody(ob); + + if(me->totvert) { bp= ob->soft->bpoint; for(a=0; atotvert; a++, mvert++, bp++) { @@ -605,30 +623,39 @@ static void mesh_update_softbody(Object *ob) Mat4MulVecfl(ob->obmat, bp->origE); VECCOPY(bp->origT, bp->origE); } - /* hrms .. do springs alter their lenght ? - if(medge) { - bs= ob->soft->bspring; - bp= ob->soft->bpoint; - for(a=0; (atotedge && a < ob->soft->totspring ); a++, medge++, bs++) { - bs->len= VecLenf( (bp+bs->v1)->origE, (bp+bs->v2)->origE); + + if(ob->softflag & OB_SB_EDGES) { + + /* happens when in UI edges was set */ + if(ob->soft->bspring==NULL) + if(object_has_edges(ob)) sbObjectToSoftbody(ob); + + /* hrms .. do springs alter their lenght ? + if(medge) { + bs= ob->soft->bspring; + bp= ob->soft->bpoint; + for(a=0; (atotedge && a < ob->soft->totspring ); a++, medge++, bs++) { + bs->len= VecLenf( (bp+bs->v1)->origE, (bp+bs->v2)->origE); + } } + */ } - */ } } -int get_scalar_from_named_vertexgroup(Object *ob, char *name, int vertID, float *target) +static int get_scalar_from_named_vertexgroup(Object *ob, char *name, int vertID, float *target) /* result 0 on success, else indicates error number -- kind of *inverse* result defintion, -- but this way we can signal error condition to caller -- and yes this function must not be here but in a *vertex group module* */ { - int i,groupindex; bDeformGroup *locGroup = NULL; MDeformVert *dv; + int i, groupindex; + locGroup = get_named_vertexgroup(ob,name); if(locGroup){ /* retrieve index for that group */ @@ -654,61 +681,65 @@ int get_scalar_from_named_vertexgroup(Object *ob, char *name, int vertID, float /* makes totally fresh start situation */ static void mesh_to_softbody(Object *ob) { + SoftBody *sb; Mesh *me= ob->data; MVert *mvert= me->mvert; MEdge *medge= me->medge; -/* MFace *mface= me->mface; */ /*unused*/ BodyPoint *bp; BodySpring *bs; int a; - ob->soft= new_softbody(me->totvert, me->totedge); - if(ob->soft) { - bp= ob->soft->bpoint; - for(a=me->totvert; a>0; a--, mvert++, bp++) { - VECCOPY(bp->pos, mvert->co); - Mat4MulVecfl(ob->obmat, bp->pos); // yep, sofbody is global coords - VECCOPY(bp->origS, bp->pos); - VECCOPY(bp->origE, bp->pos); - VECCOPY(bp->origT, bp->pos); - bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0; - bp->weight= 1.0; - bp->goal= 0.5; - bp->nofsprings=0; - bp->springs=NULL; - if (1) { /* switch to vg scalars*/ - /* get scalar values needed *per vertex* from vertex group functions, - so we can *paint* them nicly .. - they are normalized [0.0..1.0] so may be we need amplitude for scale - which can be done by caller - but still .. i'd like it to go this way - */ - int error; - char name[32] = "SOFTGOAL"; - float temp; - error = get_scalar_from_named_vertexgroup(ob,name,me->totvert - a,&temp); - if (!error) bp->goal = temp; - if (bp->goal < ob->sb_mingoal) bp->goal = ob->sb_mingoal; - if (bp->goal > ob->sb_maxgoal) bp->goal = ob->sb_maxgoal; - /* a little ad hoc changing the goal control to be less *sharp* */ - bp->goal = (float)pow(bp->goal,4.0f); -/* to proove the concept -this would enable per vertex *mass painting* - strcpy(name,"SOFTMASS"); - error = get_scalar_from_named_vertexgroup(ob,name,me->totvert - a,&temp); - if (!error) bp->mass = temp * ob->rangeofmass; -*/ - + /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ + renew_softbody(ob, me->totvert, me->totedge); + + /* we always make body points */ + sb= ob->soft; + bp= sb->bpoint; + for(a=me->totvert; a>0; a--, mvert++, bp++) { + VECCOPY(bp->pos, mvert->co); + Mat4MulVecfl(ob->obmat, bp->pos); // yep, sofbody is global coords + VECCOPY(bp->origS, bp->pos); + VECCOPY(bp->origE, bp->pos); + VECCOPY(bp->origT, bp->pos); + bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0; + bp->weight= 1.0; + bp->goal= 0.5; + bp->nofsprings=0; + bp->springs=NULL; + if (1) { /* switch to vg scalars*/ + /* get scalar values needed *per vertex* from vertex group functions, + so we can *paint* them nicly .. + they are normalized [0.0..1.0] so may be we need amplitude for scale + which can be done by caller + but still .. i'd like it to go this way + */ + int error; + char name[32] = "SOFTGOAL"; + float temp; + + error = get_scalar_from_named_vertexgroup(ob,name,me->totvert - a,&temp); + if (!error) bp->goal = temp; + if (bp->goal < sb->mingoal) bp->goal = sb->mingoal; + if (bp->goal > sb->maxgoal) bp->goal = sb->maxgoal; + /* a little ad hoc changing the goal control to be less *sharp* */ + bp->goal = (float)pow(bp->goal,4.0f); + /* to proove the concept + this would enable per vertex *mass painting* + strcpy(name,"SOFTMASS"); + error = get_scalar_from_named_vertexgroup(ob,name,me->totvert - a,&temp); + if (!error) bp->mass = temp * ob->rangeofmass; + */ - } /* switch to vg scalars */ - } - + } /* switch to vg scalars */ + } + /* but we only optionally add body edge springs */ + if (ob->softflag & OB_SB_EDGES) { if(medge) { - bs= ob->soft->bspring; - bp= ob->soft->bpoint; + bs= sb->bspring; + bp= sb->bpoint; for(a=me->totedge; a>0; a--, medge++, bs++) { bs->v1= medge->v1; bs->v2= medge->v2; @@ -718,44 +749,11 @@ this would enable per vertex *mass painting* } /* insert *diagonal* springs in quads if desired */ - if (ob->softflag & 0x02) { - add_quad_diag_springs(ob); - + if (ob->softflag & OB_SB_QUADS) { + add_mesh_quad_diag_springs(ob); } build_bps_springlist(ob); /* big mesh optimization */ - - /* vertex colors are abused as weights here, however they're stored in faces... uhh */ - /* naah .. we don't do it any more bjornmose :-) - if(mface && me->mcol) { - char *mcol= (char *)me->mcol; - for(a=me->totface; a>0; a--, mface++, mcol+=16) { - bp= ob->soft->bpoint+mface->v1; - if(bp->goal==0.5) { - bp->goal= ( (float)( (mcol + 0)[1] ) )/255.0; - } - bp= ob->soft->bpoint+mface->v2; - if(bp->goal==0.5) { - bp->goal= ( (float)( (mcol + 4)[1] ) )/255.0; - } - bp= ob->soft->bpoint+mface->v3; - if(bp->goal==0.5) { - bp->goal= ( (float)( (mcol + 8)[1]) )/255.0; - } - if(mface->v4) { - bp= ob->soft->bpoint+mface->v4; - if(bp->goal==0.5) { - bp->goal= ( (float)( (mcol + 12)[1]) )/255.0; - } - } - } - } - */ - bp= ob->soft->bpoint; - for(a=me->totvert; a>0; a--, bp++) { - //printf("a %d goal %f\n", a, bp->goal); - } - } } @@ -790,142 +788,174 @@ static void softbody_to_lattice(Object *ob) } - - -/* ************ Object level, exported functions *************** */ +/* copies softbody result back in object */ +/* only used in sbObjectStep() */ +static void softbody_to_object(Object *ob) +{ + + if(ob->soft==NULL) return; + + switch(ob->type) { + case OB_MESH: + softbody_to_mesh(ob); + break; + case OB_LATTICE: + softbody_to_lattice(ob); + break; + } +} /* copy original (new) situation in softbody, as result of matrices or deform */ -void object_update_softbody(Object *ob) +/* used in sbObjectStep() and sbObjectReset() */ +/* assumes to have ob->soft, but can be entered without points */ +static void object_update_softbody(Object *ob) { + switch(ob->type) { - case OB_MESH: - mesh_update_softbody(ob); - break; - case OB_LATTICE: - //lattice_update_softbody(ob); - break; + case OB_MESH: + mesh_update_softbody(ob); + break; + case OB_LATTICE: + //lattice_update_softbody(ob); + break; } + +} + + + +/* ************ Object level, exported functions *************** */ +/* allocates and initializes general main data */ +SoftBody *sbNew(void) +{ + SoftBody *sb; + + sb= MEM_callocN(sizeof(SoftBody), "softbody"); + + sb->mediafrict= 1.0; + sb->nodemass= 1.0; + sb->grav= 0.0; + + sb->goalspring= 1.0; + sb->goalfrict= 1.0; + sb->mingoal= 0.0; + sb->maxgoal= 1.0; + + sb->inspring= 1.0; + sb->infrict= 1.0; + + return sb; +} + +/* frees all */ +void sbFree(SoftBody *sb) +{ + free_softbody_intern(sb); + MEM_freeN(sb); } + /* makes totally fresh start situation */ -void object_to_softbody(Object *ob,float ctime) +void sbObjectToSoftbody(Object *ob) { - if(ob->soft) free_softbody(ob->soft); - ob->soft= NULL; - switch(ob->type) { case OB_MESH: mesh_to_softbody(ob); - ob->soft->ctime = ctime; break; case OB_LATTICE: lattice_to_softbody(ob); break; } + + if(ob->soft) ob->soft->ctime= bsystem_time(ob, NULL, (float)G.scene->r.cfra, 0.0); } -/* copies softbody result back in object */ -void softbody_to_object(Object *ob) +/* reset all motion */ +void sbObjectReset(Object *ob) { - - if(ob->soft==NULL) return; + SoftBody *sb= ob->soft; + BodyPoint *bp; + int a; - switch(ob->type) { - case OB_MESH: - softbody_to_mesh(ob); - break; - case OB_LATTICE: - softbody_to_lattice(ob); - break; + if(sb==NULL) return; + sb->ctime= bsystem_time(ob, NULL, (float)G.scene->r.cfra, 0.0); + + object_update_softbody(ob); + + for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { + // origS is previous timestep + VECCOPY(bp->origS, bp->origE); + VECCOPY(bp->pos, bp->origE); + bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0f; + // no idea about the Heun stuff! (ton) } } -/* simulates one step. ctime is in frames not seconds */ - -void object_softbody_step(Object *ob, float ctime) +/* simulates one step. framenr is in frames */ +/* copies result back to object, displist */ +void sbObjectStep(Object *ob, float framenr) { + SoftBody *sb; float dtime; int timescale,t; - float forcetime; + float ctime, forcetime; float err; - /* this is a NO! NO! - ========================== - if(ob->soft==NULL) { - object_to_softbody(ob); - if(ob->soft==NULL) return; - ob->soft->ctime= ctime; - } - // you can't create a soft object on the fly - // 1. inner spings need a *default* length for crinkles/wrinkles, - // surface area and volume preservation - // 2. initial conditions for velocities and positions need to be defined - // for a certain point of time .. say t0 - // 3. and since we have friction and *outer* movement - // the history of the *outer* movements will affect where we end up - // sooo atm going to edit mode and back ( back calls object_to_softbody(ob,1.0f) - is the only way to create softbody data - */ - - /* first attempt to set initial conditions for softbodies - rules - 1. ODE solving is disabled / via button in 3dview header /otherways do regular softbody stuff - 2. set SB positions to *goal* - 3. set SB velocities to match *goal* movement - - */ - if (SB_ENABLE == 0){ - if(ob->soft==NULL) { - return; /* nothing to do */ - } - object_update_softbody(ob); - ob->soft->ctime= ctime; - interpolate_exciter(ob,200,200); - softbody_force_goal(ob); - softbody_to_object(ob); - return; /* no dynamics wanted */ - - } - - if(ob->soft==NULL) { - /* aye no soft object created bail out here */ - printf("Softbody Zombie \n"); + /* just to be nice we allow full init */ + if(ob->soft==NULL) sbObjectToSoftbody(ob); + /* this is after reading new file, or acceptable as signal to refresh */ + else if(ob->soft->totpoint==0) sbObjectToSoftbody(ob); + + sb= ob->soft; + + /* still no points? go away */ + if(sb->totpoint==0) return; + + /* checking time: */ + ctime= bsystem_time(ob, NULL, framenr, 0.0); + softbody_scale_time(steptime); // translate frames/sec and lenghts unit to SI system + dtime= ctime - sb->ctime; + // dtime= ABS(dtime); no no we want to go back in time with IPOs + timescale = (int)(sb->rklimit * ABS(dtime)); + // bail out for negative or for large steps + if(dtime<0.0 || dtime >= 9.9*G.scene->r.framelen) { + sbObjectReset(ob); return; } - softbody_scale_time(steptime); // translate frames/sec and lenghts unit to SI system - dtime= ctime - ob->soft->ctime; - // dtime= ABS(dtime); no no we want to go back in time with IPOs - timescale = (int)(ob->softtime * ABS(dtime)); - if(ABS(dtime) > 0.0) { + /* the simulator */ + + if(ABS(dtime) > 0.0) { // note: what does this mean now? (ton) + object_update_softbody(ob); - if (ob->softflag & 0x04){ + + if (TRUE) { // RSOL1 always true now (ton) /* special case of 2nd order Runge-Kutta type AKA Heun */ float timedone =0.0; /* counter for emergency brake * we don't want to lock up the system if physics fail */ int loops =0 ; - SoftHeunTol = ob->softtime; // humm .. this should be calculated from sb parameters and sizes + SoftHeunTol = sb->rklimit; // humm .. this should be calculated from sb parameters and sizes forcetime = dtime; /* hope for integrating in one step */ while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) ) { if (ABS(dtime) > 3.0 ){ - printf("SB_STEPSIZE \n"); + if(G.f & G_DEBUG) printf("SB_STEPSIZE \n"); break; // sorry but i must assume goal movement can't be interpolated any more } //set goals in time interpolate_exciter(ob,200,(int)(200.0*(timedone/dtime))); // do predictive euler step - softbody_calc_forces(ob,forcetime); - softbody_apply_forces(ob,forcetime,1, NULL); + softbody_calc_forces(ob, forcetime); + softbody_apply_forces(ob, forcetime, 1, NULL); // crop new slope values to do averaged slope step - softbody_calc_forces(ob,forcetime); - softbody_apply_forces(ob,forcetime,2, &err); + softbody_calc_forces(ob, forcetime); + softbody_apply_forces(ob, forcetime, 2, &err); softbody_apply_goalsnap(ob); if (err > SoftHeunTol){ // error needs to be scaled to some quantity @@ -933,24 +963,27 @@ void object_softbody_step(Object *ob, float ctime) forcetime /= 2.0; } else { - float newtime = forcetime * 1.1f; // hope for 1.1 times better conditions in next step + if (err > SoftHeunTol/2.0){ // stay with this stepsize unless err really small newtime = forcetime; } timedone += forcetime; if (forcetime > 0.0) - forcetime = MIN2(dtime - timedone,newtime); + forcetime = MIN2(dtime - timedone,newtime); else - forcetime = MAX2(dtime - timedone,newtime); + forcetime = MAX2(dtime - timedone,newtime); } loops++; } // move snapped to final position - interpolate_exciter(ob,2,2); + interpolate_exciter(ob, 2, 2); softbody_apply_goalsnap(ob); - if (loops > HEUNWARNLIMIT) /* monitor high loop counts say 1000 after testing */ - printf("%d heun integration loops/frame \n",loops); + + if(G.f & G_DEBUG) { + if (loops > HEUNWARNLIMIT) /* monitor high loop counts say 1000 after testing */ + printf("%d heun integration loops/frame \n",loops); + } } else /* do brute force explicit euler */ @@ -965,44 +998,42 @@ void object_softbody_step(Object *ob, float ctime) /* the *goal* mesh must use the n*h timing too ! use *cheap* linear intepolation for that */ interpolate_exciter(ob,timescale,t); - if (timescale > 0 ) - { - forcetime = dtime/timescale; - - /* does not fit the concept sloving ODEs :) */ - /* softbody_apply_goal(ob,forcetime ); */ - - /* explicit Euler integration */ - /* we are not controling a nuclear power plant! - so rought *almost* physical behaviour is acceptable. - in cases of *mild* stiffnes cranking up timscale -> decreasing stepsize *h* - avoids instability */ - softbody_calc_forces(ob,forcetime); - softbody_apply_forces(ob,forcetime,0, NULL); - softbody_apply_goalsnap(ob); - + if (timescale > 0 ) { + forcetime = dtime/timescale; + + /* does not fit the concept sloving ODEs :) */ + /* softbody_apply_goal(ob,forcetime ); */ + + /* explicit Euler integration */ + /* we are not controling a nuclear power plant! + so rought *almost* physical behaviour is acceptable. + in cases of *mild* stiffnes cranking up timscale -> decreasing stepsize *h* + avoids instability */ + softbody_calc_forces(ob,forcetime); + softbody_apply_forces(ob,forcetime,0, NULL); + softbody_apply_goalsnap(ob); -// if (0){ - /* ok here comes the überhammer - use a semi implicit euler integration to tackle *all* stiff conditions - but i doubt the cost/benifit holds for most of the cases - -- to be coded*/ -// } - + // if (0){ + /* ok here comes the überhammer + use a semi implicit euler integration to tackle *all* stiff conditions + but i doubt the cost/benifit holds for most of the cases + -- to be coded*/ + // } + } } /* and apply to vertices */ softbody_to_object(ob); - ob->soft->ctime= ctime; + sb->ctime= ctime; } // if(ABS(dtime) > 0.0) else { - // rule : you have asked for the current state of the softobject - // since dtime= ctime - ob->soft->ctime; - // and we were not notifified about any other time changes - // so here it is ! - softbody_to_object(ob); + // rule : you have asked for the current state of the softobject + // since dtime= ctime - ob->soft->ctime; + // and we were not notifified about any other time changes + // so here it is ! + softbody_to_object(ob); } } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 6561318cd8b..000a9261d37 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -119,6 +119,7 @@ #include "BKE_object.h" #include "BKE_sca.h" // for init_actuator #include "BKE_scene.h" +#include "BKE_softbody.h" // sbNew() #include "BKE_texture.h" // for open_plugin_tex #include "BKE_utildefines.h" // SWITCH_INT DATA ENDB DNA1 O_BINARY GLOB USER TEST REND @@ -2316,7 +2317,13 @@ static void direct_link_object(FileData *fd, Object *ob) } ob->pd= newdataadr(fd, ob->pd); - ob->soft= NULL; + ob->soft= newdataadr(fd, ob->soft); + if(ob->soft) { + SoftBody *sb= ob->soft; // init all stuff so it gets rebuilt nicely + sb->totpoint= sb->totspring= 0; + sb->bpoint= NULL; + sb->bspring= NULL; + } link_list(fd, &ob->prop); prop= ob->prop.first; @@ -4625,6 +4632,7 @@ static void do_versions(Main *main) } } if(main->versionfile <= 236) { + Object *ob; Scene *sce= main->scene.first; Camera *cam= main->camera.first; bScreen *sc; @@ -4653,6 +4661,26 @@ static void do_versions(Main *main) } } } + /* temporal copy */ + for(ob= main->object.first; ob; ob= ob->id.next) { + if(ob->softflag && ob->soft==NULL) { + SoftBody *sb; + ob->soft=sb= sbNew(); + + sb->goalspring= ob->sb_goalspring; + sb->goalfrict= ob->sb_goalfrict; + sb->inspring= ob->sb_inspring; + sb->infrict= ob->sb_infrict; + sb->nodemass= ob->sb_nodemass; + sb->grav= ob->sb_grav; + sb->mingoal= ob->sb_mingoal; + sb->maxgoal= ob->sb_maxgoal; + sb->mediafrict= ob->sb_mediafrict; + sb->rklimit= ob->softtime; + + ob->softflag |= OB_SB_GOAL|OB_SB_EDGES; + } + } } /* don't forget to set version number in blender.c! */ diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 054024b4d75..00b29f32127 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -683,6 +683,7 @@ static void write_objects(WriteData *wd, ListBase *idbase) write_nlastrips(wd, &ob->nlastrips); writestruct(wd, DATA, "PartDeflect", 1, ob->pd); + writestruct(wd, DATA, "SoftBody", 1, ob->soft); for(hook= ob->hooks.first; hook; hook= hook->next) { writestruct(wd, DATA, "ObHook", 1, hook); diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 8c52da30bc0..4addd3ddff0 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -51,7 +51,8 @@ struct BoundBox; struct Path; struct Material; struct bConstraintChannel; -struct SoftBody; +struct BodyPoint; +struct BodySpring; typedef struct bDeformGroup { struct bDeformGroup *next, *prev; @@ -90,6 +91,31 @@ typedef struct PartDeflect { float f_power; /* The power law - real gravitation is 2 (square) */ } PartDeflect; +typedef struct SoftBody { + /* dynamic data */ + int totpoint, totspring; + struct BodyPoint *bpoint; /* not saved in file */ + struct BodySpring *bspring; /* not saved in file */ + float ctime; /* last time calculated */ + + /* part of UI: */ + float nodemass; /* softbody mass of *vertex* */ + float grav; /* softbody amount of gravitaion to apply */ + float mediafrict; /* friction to env */ + float rklimit; /* error limit for ODE solver */ + + float goalspring; /* softbody goal springs */ + float goalfrict; /* softbody goal springs friction */ + float mingoal; /* quick limits for goal */ + float maxgoal; + + float inspring; /* softbody inner springs */ + float infrict; /* softbody inner springs friction */ + + float pad; + +} SoftBody; + typedef struct Object { ID id; @@ -150,7 +176,7 @@ typedef struct Object { * For a Sphere, the form factor is by default = 0.4 */ - float formfactor, softtime; /* springf temp for softbody */ + float formfactor, softtime; /* softtime temp for softbody, remove it before release! */ float rdamping, sizefac; char dt, dtx; @@ -194,7 +220,7 @@ typedef struct Object { ListBase hooks; PartDeflect *pd; /* particle deflector/attractor/collision data */ - struct SoftBody *soft; /* only runtime, not saved in file! */ + struct SoftBody *soft; /* if exists, saved in file */ struct Life *life; LBuf lbuf; @@ -387,6 +413,14 @@ extern Object workob; #define OB_ADDACT 1024 #define OB_SHOWCONT 2048 +/* ob->softflag */ +#define OB_SB_ENABLE 1 +#define OB_SB_GOAL 2 +#define OB_SB_EDGES 4 +#define OB_SB_QUADS 8 +#define OB_SB_POSTDEF 16 + + #ifdef __cplusplus } #endif diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 0db5a750cf7..f9533f0ebd7 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -47,6 +47,7 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_library.h" +#include "BKE_softbody.h" #include "BLI_blenlib.h" #include "BLI_arithb.h" @@ -1439,34 +1440,6 @@ static void object_panel_deflectors(Object *ob) } uiBlockEndAlign(block); } -/* - if(strncmp(ob->id.name+2, "soft", 4)==0) { - int ypos = 220; - uiBlockBeginAlign(block); - uiDefButS(block, TOG|BIT|0, B_DIFF, "Soft Body", 220,ypos,200,20, &ob->softflag, 0, 0, 0, 0, "Sets object to become soft body"); - - uiDefButS(block, TOG|BIT|1, B_DIFF, "Stiff Quads", 220,ypos -= 20,100,20, &ob->softflag, 0, 0, 0, 0, "Sets object to have diagonal springs on 4-gons"); - uiDefButS(block, TOG|BIT|2, B_DIFF, "R sol 1", 320,ypos,100,20, &ob->softflag, 0, 0, 0, 0, "Use Robust 2nd order solver"); - - uiDefButF(block, NUMSLI, B_DIFF, "GSpring:", 220,ypos -= 20,200,20, &ob->sb_goalspring, 0.0, 0.999, 10, 0, "Goal Spring Constant"); - uiDefButF(block, NUM, B_DIFF, "GFrict:", 220,ypos -= 20,200,20, &ob->sb_goalfrict , 0.0, 10.0, 10, 0, "Goal Friction Constant"); - uiDefButF(block, NUMSLI, B_DIFF, "ISpring:", 220,ypos -= 20,200,20, &ob->sb_inspring, 0.0, 0.999, 10, 0, "Inner Spring Constant"); - uiDefButF(block, NUM, B_DIFF, "IFrict:", 220,ypos -= 20,200,20, &ob->sb_infrict, 0.0, 10.0, 10, 0, "Inner Friction Constant"); - uiDefButF(block, NUM, B_DIFF, "MFrict:", 220,ypos -= 20,200,20, &ob->sb_mediafrict, 0.0, 10.0, 10, 0, "Friction in media"); - - if (ob->softflag & 0x4) - uiDefButF(block, NUMSLI, B_DIFF, "RKL:", 220,ypos -= 20,200,20, &ob->softtime , 0.01, 1.0, 10, 0, "ODE solver error limit"); - else - uiDefButF(block, NUM, B_DIFF, "Steps:", 220,ypos -= 20,200,20, &ob->softtime , 1.0, 500.0, 10, 0, "Softbody time"); - - uiDefButF(block, NUM, B_DIFF, "NMass:", 220,ypos -= 20,200,20, &ob->sb_nodemass , 0.001, 50.0, 10, 0, "Node Mass"); - uiDefButF(block, NUM, B_DIFF, "Grav:", 220,ypos -= 20,200,20, &ob->sb_grav , 0.0, 10.0, 10, 0, "Gravitation"); - uiDefButF(block, NUMSLI, B_DIFF, "GMin:", 220,ypos -= 20,200,20, &ob->sb_mingoal, 0.0, 1.0, 10, 0, "Min Goal bound"); - uiDefButF(block, NUMSLI, B_DIFF, "GMax:", 220,ypos -= 20,200,20, &ob->sb_maxgoal, 0.0, 1.0, 10, 0, "Max Goal bound"); - uiDefButS(block, TOG|BIT|3, B_DIFF, "PostDef",220,ypos-= 20,100,20, &ob->softflag, 0, 0, 0, 0, "Apply Soft AFTER Deform"); - uiBlockEndAlign(block); - } -*/ } /* Panel for softbodies */ @@ -1474,36 +1447,50 @@ static void object_panel_deflectors(Object *ob) static void object_softbodies(Object *ob) { uiBlock *block; - int ypos = 220; - if(strncmp(ob->id.name+2, "soft", 4)!=0) {return;} + block= uiNewBlock(&curarea->uiblocks, "object_softbodies", UI_EMBOSS, UI_HELV, curarea->win); uiNewPanelTabbed("Constraints", "Object"); - if(uiNewPanel(curarea, block, "Softbodies", "Object", 640, 0, 318, 204)==0) return; + if(uiNewPanel(curarea, block, "Softbody", "Object", 640, 0, 318, 204)==0) return; - uiBlockBeginAlign(block); - uiDefButS(block, TOG|BIT|0, REDRAWBUTSOBJECT, "Soft Body", 220,ypos,200,20, &ob->softflag, 0, 0, 0, 0, "Sets object to become soft body"); - if ( ob->softflag & 0x01) { - uiDefButS(block, TOG|BIT|1, B_DIFF, "Stiff Quads", 220,ypos -= 20,100,20, &ob->softflag, 0, 0, 0, 0, "Sets object to have diagonal springs on 4-gons"); - uiDefButS(block, TOG|BIT|2, B_DIFF, "R sol 1", 320,ypos,100,20, &ob->softflag, 0, 0, 0, 0, "Use Robust 2nd order solver"); + uiDefButBitS(block, TOG, OB_SB_ENABLE, REDRAWBUTSOBJECT, "Enable Soft Body", 10,200,150,20, &ob->softflag, 0, 0, 0, 0, "Sets object to become soft body"); + uiDefBut(block, LABEL, 0, "", 160, 200,150,20, NULL, 0.0, 0.0, 0, 0, ""); // alignment reason + + if(ob->softflag & OB_SB_ENABLE) { + SoftBody *sb= ob->soft; - uiDefButF(block, NUMSLI, B_DIFF, "GSpring:", 220,ypos -= 20,200,20, &ob->sb_goalspring, 0.0, 0.999, 10, 0, "Goal Spring Constant"); - uiDefButF(block, NUM, B_DIFF, "GFrict:", 220,ypos -= 20,200,20, &ob->sb_goalfrict , 0.0, 10.0, 10, 0, "Goal Friction Constant"); - uiDefButF(block, NUMSLI, B_DIFF, "ISpring:", 220,ypos -= 20,200,20, &ob->sb_inspring, 0.0, 0.999, 10, 0, "Inner Spring Constant"); - uiDefButF(block, NUM, B_DIFF, "IFrict:", 220,ypos -= 20,200,20, &ob->sb_infrict, 0.0, 10.0, 10, 0, "Inner Friction Constant"); - uiDefButF(block, NUM, B_DIFF, "MFrict:", 220,ypos -= 20,200,20, &ob->sb_mediafrict, 0.0, 10.0, 10, 0, "Friction in media"); - - if (ob->softflag & 0x4) - uiDefButF(block, NUMSLI, B_DIFF, "RKL:", 220,ypos -= 20,200,20, &ob->softtime , 0.01, 1.0, 10, 0, "ODE solver error limit"); - else - uiDefButF(block, NUM, B_DIFF, "Steps:", 220,ypos -= 20,200,20, &ob->softtime , 1.0, 500.0, 10, 0, "Softbody time"); - - uiDefButF(block, NUM, B_DIFF, "NMass:", 220,ypos -= 20,200,20, &ob->sb_nodemass , 0.001, 50.0, 10, 0, "Node Mass"); - uiDefButF(block, NUM, B_DIFF, "Grav:", 220,ypos -= 20,200,20, &ob->sb_grav , 0.0, 10.0, 10, 0, "Gravitation"); - uiDefButF(block, NUMSLI, B_DIFF, "GMin:", 220,ypos -= 20,200,20, &ob->sb_mingoal, 0.0, 1.0, 10, 0, "Min Goal bound"); - uiDefButF(block, NUMSLI, B_DIFF, "GMax:", 220,ypos -= 20,200,20, &ob->sb_maxgoal, 0.0, 1.0, 10, 0, "Max Goal bound"); - uiDefButS(block, TOG|BIT|3, B_DIFF, "PostDef",220,ypos-= 20,100,20, &ob->softflag, 0, 0, 0, 0, "Apply Soft AFTER Deform"); + if(sb==NULL) { + sb= ob->soft= sbNew(); + ob->softflag |= OB_SB_GOAL|OB_SB_EDGES; } + + /* GENERAL STUFF */ + uiBlockBeginAlign(block); + uiDefButF(block, NUM, B_DIFF, "Friction:", 10, 170,150,20, &sb->mediafrict, 0.0, 10.0, 10, 0, "General Friction for point movements"); + uiDefButF(block, NUM, B_DIFF, "Mass:", 160, 170,150,20, &sb->nodemass , 0.001, 50.0, 10, 0, "Point Mass, the heavier the slower"); + uiDefButF(block, NUM, B_DIFF, "Grav:", 10,150,150,20, &sb->grav , 0.0, 10.0, 10, 0, "Apply gravitation to point movement"); + uiDefButF(block, NUM, B_DIFF, "RKL:", 160,150,150,20, &sb->rklimit , 0.01, 1.0, 10, 0, "Runge-Kutta ODE solver error limit"); + uiDefButBitS(block, TOG, OB_SB_POSTDEF, B_DIFF, "PostDef", 10,130,300,20, &ob->softflag, 0, 0, 0, 0, "Apply Soft AFTER Deform"); + uiBlockEndAlign(block); + + /* GOAL STUFF */ + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, OB_SB_GOAL, B_DIFF, "Use Goal", 10,100,150,20, &ob->softflag, 0, 0, 0, 0, "Define forces for vertices to stick to animated position"); + uiDefButF(block, NUM, B_DIFF, "GSpring:", 10,80,150,20, &sb->goalspring, 0.0, 0.999, 10, 0, "Goal (vertex target position) Spring Constant"); + uiDefButF(block, NUM, B_DIFF, "GFrict:", 160,80,150,20, &sb->goalfrict , 0.0, 10.0, 10, 0, "Goal (vertex target position) Friction Constant"); + uiDefButF(block, NUM, B_DIFF, "GMin:", 10,60,150,20, &sb->mingoal, 0.0, 1.0, 10, 0, "Min Goal bound"); + uiDefButF(block, NUM, B_DIFF, "GMax:", 160,60,150,20, &sb->maxgoal, 0.0, 1.0, 10, 0, "Max Goal bound"); uiBlockEndAlign(block); + + /* EDGE SPRING STUFF */ + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, OB_SB_EDGES, B_DIFF, "Use Edges", 10,30,150,20, &ob->softflag, 0, 0, 0, 0, "Use Robust 2nd order solver"); + uiDefButBitS(block, TOG, OB_SB_QUADS, B_DIFF, "Stiff Quads", 160,30,150,20, &ob->softflag, 0, 0, 0, 0, "Sets object to have diagonal springs on 4-gons"); + uiDefButF(block, NUM, B_DIFF, "ESpring:", 10,10,150,20, &sb->inspring, 0.0, 0.999, 10, 0, "Edge Spring Constant"); + uiDefButF(block, NUM, B_DIFF, "EFrict:", 160,10,150,20, &sb->infrict, 0.0, 10.0, 10, 0, "Edge Friction Constant"); + uiBlockEndAlign(block); + + } + uiBlockEndAlign(block); } diff --git a/source/blender/src/editipo.c b/source/blender/src/editipo.c index 0db4f60ffca..8924cf6092d 100644 --- a/source/blender/src/editipo.c +++ b/source/blender/src/editipo.c @@ -1426,7 +1426,6 @@ void swap_selectall_editipo() } else if(totipo_edit==0) { ei= G.sipo->editipo; - printf("before totipo_sel %d\n", totipo_sel); if (ei){ for(a=0; atotipo; a++) { if( ei->flag & IPO_VISIBLE ) { @@ -1438,7 +1437,6 @@ void swap_selectall_editipo() update_editipo_flags(); } get_status_editipo(); - printf("after totipo_sel %d\n", totipo_sel); } else { ei= G.sipo->editipo; diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index 708e93454eb..9f0b01dc715 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -1537,13 +1537,8 @@ void exit_editmode(int freedata) /* freedata==0 at render, 1= freedata, 2= do un /* displist make is different in editmode */ if(freedata) G.obedit= NULL; -// need to be here since -// makeDispList(ob); calls -// int mesh_modifier(Object *ob, char mode).. -// calling object_softbody_step(ob, ctime); -// needs a valid *up to date* softbody object or NULL pointer at "soft" member -// anyhow *new* dependacy graph should take care for that :) - if(ob->softflag & 0x01) object_to_softbody(ob,1.0f); + /* total remake of softbody data */ + if(ob->softflag & OB_SB_ENABLE) sbObjectToSoftbody(ob); makeDispList(ob); @@ -1582,8 +1577,6 @@ void exit_editmode(int freedata) /* freedata==0 at render, 1= freedata, 2= do un allqueue(REDRAWOOPS, 0); } scrarea_queue_headredraw(curarea); -// faaaaar to late -// if(ob->softflag & 0x01) object_to_softbody(ob); if(G.obedit==NULL && freedata==2) BIF_undo_push("Editmode"); diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c index d050e5f7d24..815aeda3ccc 100644 --- a/source/blender/src/header_view3d.c +++ b/source/blender/src/header_view3d.c @@ -3361,6 +3361,7 @@ static uiBlock *view3d_faceselmenu(void *arg_unused) static char *view3d_modeselect_pup(void) { + Object *ob= OBACT; static char string[1024]; char formatstr[1024]; char tempstr[1024]; @@ -3371,16 +3372,18 @@ static char *view3d_modeselect_pup(void) sprintf(tempstr, formatstr, "Object Mode", V3D_OBJECTMODE_SEL, ICON_OBJECT); strcat(string, tempstr); + if(ob==NULL) return string; + /* if active object is editable */ - if (OBACT && ((OBACT->type == OB_MESH) || (OBACT->type == OB_ARMATURE) - || (OBACT->type == OB_CURVE) || (OBACT->type == OB_SURF) || (OBACT->type == OB_FONT) - || (OBACT->type == OB_MBALL) || (OBACT->type == OB_LATTICE))) { + if ( ((ob->type == OB_MESH) || (ob->type == OB_ARMATURE) + || (ob->type == OB_CURVE) || (ob->type == OB_SURF) || (ob->type == OB_FONT) + || (ob->type == OB_MBALL) || (ob->type == OB_LATTICE))) { sprintf(tempstr, formatstr, "Edit Mode", V3D_EDITMODE_SEL, ICON_EDITMODE_HLT); strcat(string, tempstr); } - if (OBACT && OBACT->type == OB_MESH) { + if (ob->type == OB_MESH) { sprintf(tempstr, formatstr, "UV Face Select", V3D_FACESELECTMODE_SEL, ICON_FACESEL_HLT); strcat(string, tempstr); @@ -3390,7 +3393,7 @@ static char *view3d_modeselect_pup(void) strcat(string, tempstr); - if ( ((Mesh*)(OBACT->data))->dvert) { + if ( ((Mesh*)(ob->data))->dvert) { sprintf(tempstr, formatstr, "Weight Paint", V3D_WEIGHTPAINTMODE_SEL, ICON_WPAINT_HLT); strcat(string, tempstr); } @@ -3398,7 +3401,7 @@ static char *view3d_modeselect_pup(void) /* if active object is an armature */ - if (OBACT && OBACT->type==OB_ARMATURE) { + if (ob->type==OB_ARMATURE) { sprintf(tempstr, formatstr, "Pose Mode", V3D_POSEMODE_SEL, ICON_POSE_HLT); strcat(string, tempstr); } @@ -4088,11 +4091,6 @@ void view3d_buttons(void) "Pastes the mirrored pose from the buffer"); } } - { - extern short SB_ENABLE; - xco+= XIC+8; - uiDefButS(block, TOG|BIT|1, B_DIFF, "Soft", xco,0,XIC*3,YIC, &SB_ENABLE, 0, 0, 0, 0, "Force Softbodies to goal"); - } /* Always do this last */ curarea->headbutlen= xco+2*XIC; diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c index 6a97cad660d..e3435a00600 100644 --- a/source/blender/src/usiblender.c +++ b/source/blender/src/usiblender.c @@ -160,9 +160,10 @@ static void init_userdef_file(void) } /* transform widget settings */ if(U.tw_hotspot==0) { + U.tw_flag= U_TW_ABSOLUTE; U.tw_hotspot= 14; - U.tw_size= 15; // percentage of window size - U.tw_handlesize= 25; // percentage of widget radius + U.tw_size= 20; // percentage of window size + U.tw_handlesize= 20; // percentage of widget radius } if (G.main->versionfile <= 191) { -- cgit v1.2.3