big softbody commit
authorJens Ole Wund <bjornmose@gmx.net>
Wed, 12 Jan 2005 22:28:13 +0000 (22:28 +0000)
committerJens Ole Wund <bjornmose@gmx.net>
Wed, 12 Jan 2005 22:28:13 +0000 (22:28 +0000)
some vertex group , weight painting stuff too
/me crosses fingers it does not break anything

13 files changed:
source/blender/blenkernel/BKE_softbody.h
source/blender/blenkernel/intern/deform.c
source/blender/blenkernel/intern/displist.c
source/blender/blenkernel/intern/softbody.c
source/blender/include/butspace.h
source/blender/makesdna/DNA_object_types.h
source/blender/render/intern/source/initrender.c
source/blender/src/buttons_editing.c
source/blender/src/buttons_object.c
source/blender/src/drawobject.c
source/blender/src/editmesh_tools.c
source/blender/src/editobject.c
source/blender/src/header_view3d.c

index 77a683178180d6d8b2957d50974de93174643744..24abff44a2b1af260002baf0563e291780aec3b2 100644 (file)
 #define BKE_SOFTBODY_H
 
 typedef struct BodyPoint {
-       float orig[3], pos[3], vec[3], force[3];
+       float origS[3], origE[3], origT[3], pos[3], vec[3], force[3];
        float weight, goal;
+       float prevpos[3], prevvec[3], prevdx[3], prevdv[3]; /* used for Heun integration */
+    int nofsprings; int *springs;
 } BodyPoint;
 
 typedef struct BodySpring {
@@ -57,7 +59,7 @@ typedef struct SoftBody {
 extern void free_softbody(SoftBody *sb);
 
 /* makes totally fresh start situation */
-extern void object_to_softbody(Object *ob);
+extern void object_to_softbody(Object *ob,float ctime);
 
 /* copy original (but new) situation in softbody, as result of matrices or deform */
 void object_update_softbody(Object *ob);
index 16145ca2d63b1cd640420f37333c5c9bad86cbbc..19c2f15e7d3eceedd4cb7fa60723964570a427f0 100644 (file)
@@ -227,7 +227,7 @@ int mesh_modifier(Object *ob, char mode)
        else if(ob->effect.first);      // weak... particles too
        else if(ob->parent && ob->parent->type==OB_LATTICE);
        else if(ob->parent && ob->partype==PARSKEL); 
-       else if(ob->softflag);
+       else if(ob->softflag & 0x01);
        else return 0;
        
        if(me->totvert==0) return 0;
@@ -249,15 +249,21 @@ int mesh_modifier(Object *ob, char mode)
                }
                
                if(ob->effect.first) done |= object_wave(ob);
-               
-               if(ob->softflag) {
+
+               if((ob->softflag & 0x01) && !(ob->softflag & 0x08)) {
                        float ctime= bsystem_time(ob, NULL, (float)G.scene->r.cfra, 0.0);
                        done= 1;
                        object_softbody_step(ob, ctime);
                }
-               
+
                /* deform: input mesh, output ob dl_verts. is used by subsurf (output should be in mesh ton!) */
                done |= object_deform(ob);      
+
+               if((ob->softflag & 0x01) && (ob->softflag & 0x08)) {
+                       float ctime= bsystem_time(ob, NULL, (float)G.scene->r.cfra, 0.0);
+                       done= 1;
+                       object_softbody_step(ob, ctime);
+               }
                
                /* put deformed vertices in dl->verts, optional subsurf will replace that */
                if(done) {
index 228588e2c4a43fef5bd9eeb163a47b3417b795c0..9c24e6361a0e6d1d40ec5f6c85c47908ea9aaa67 100644 (file)
@@ -2405,7 +2405,7 @@ void test_all_displists(void)
                                }
                        }
                        
-                       if(ob->softflag) freedisplist_object(ob);
+                       if(ob->softflag & 0x01) freedisplist_object(ob);
                        /* warn, ob pointer changed in case of OB_MALL */
 
                        if ELEM(ob->type, OB_CURVE, OB_SURF) {
index 0c785041bb936699eb0fbce1fcec12f3cb2b8197..b56dec5417b0bcad3993e77ab16d1fc4a40432a7 100644 (file)
  * ***** END GPL/BL DUAL LICENSE BLOCK *****
  */
 
+/*
+******
+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 
+  
+  
+
+*****
+*/
+
+
 #include <math.h>
 #include <stdlib.h>
 
 #include "BKE_softbody.h"
 #include "BKE_displist.h"
 
+#include  "BIF_editdeform.h"
 /* ********** soft body engine ******* */
+#define SOFTGOALSNAP  0.999f 
+// if bp-> goal is above make it a *forced follow original* and skip all ODE stuff for this bp
+// removes *unnecessary* stiffnes from ODE system
+#define HEUNWARNLIMIT 1 // 50 would be fine i think for detecting severe *stiff* stuff
+
+float SoftHeunTol = 1.0f; // humm .. this should be calculated from sb parameters and sizes
+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
+
+
+void softbody_scale_time(float steptime)
+{
+  rescale_grav_to_framerate = steptime*steptime; 
+  rescale_friction_to_framerate = steptime;
+}
+
+
+static int count_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++;}
+       }       
+       return result;
+}
+
+static void add_quad_diag_springs(Object *ob)
+{
+       Mesh *me= ob->data;
+       MFace *mface= me->mface;
+       BodyPoint *bp;
+       BodySpring *bs, *bs_new;
+       int a ;
+       
+       if (ob->soft){
+               int nofquads;   
+               nofquads = count_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;   
+                       /* 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) 
+                                       {
+                                               bs->v1= mface->v1;
+                                               bs->v2= mface->v3;
+                                               bs->strength= 1.0;
+                                               bs->len= VecLenf( (bp+bs->v1)->origS, (bp+bs->v2)->origS);
+                                               bs++;
+                                               bs->v1= mface->v2;
+                                               bs->v2= mface->v4;
+                                               bs->strength= 1.0;
+                                               bs->len= VecLenf( (bp+bs->v1)->origS, (bp+bs->v2)->origS);
+                                               bs++;
+                                               
+                                       }
+                               }       
+                       }
+                       
+            /* now we can announce new springs */
+                       ob->soft->totspring += nofquads *2;
+                       
+               }
+       }
+}
+
+
+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;
+               bp->nofsprings = 1;
+       }
+       else {
+               bp->nofsprings++;
+               newlist = MEM_callocN(bp->nofsprings * sizeof(int), "bpsprings");
+               memcpy(newlist,bp->springs,(bp->nofsprings-1)* sizeof(int));
+               MEM_freeN(bp->springs);
+               bp->springs = newlist;
+               bp->springs[bp->nofsprings-1] = 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)
+{
+       SoftBody *sb= ob->soft; // is supposed to be there
+       BodyPoint *bp;  
+       BodySpring *bs; 
+       
+       int a,b;
+       if (!sb) 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++) {
+                       if (( (sb->totpoint-a) == bs->v1) ){ 
+                               add_bp_springlist(bp,sb->totspring -b);
+                       }
+                       if (( (sb->totpoint-a) == bs->v2) ){ 
+                               add_bp_springlist(bp,sb->totspring -b);
+                       }
+               }//for springs
+               if (bp->nofsprings) printf(" node %d has %d spring links\n",a,bp->nofsprings);
+       }//for bp               
+}
+
 
 
 static SoftBody *new_softbody(int totpoint, int totspring)  
@@ -73,80 +219,361 @@ static SoftBody *new_softbody(int totpoint, int totspring)
 void free_softbody(SoftBody *sb)
 {
        if(sb) {
-               if(sb->bpoint) MEM_freeN(sb->bpoint);
+               int a;
+               BodyPoint *bp;
+               if(sb->bpoint){
+                       for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+                               /* free spring list */ 
+                               if (bp->springs != NULL) {
+                                       MEM_freeN(bp->springs);
+                               }
+                       }
+                       MEM_freeN(sb->bpoint);
+               }
                if(sb->bspring) MEM_freeN(sb->bspring);
-               
                MEM_freeN(sb);
        }
 }
+/* ************ dynamics ********** */
+
+/* aye this belongs to arith.c */
+void Vec3PlusStVec(float *v, float s, float *v1)
+{
+       v[0] += s*v1[0];
+       v[1] += s*v1[1];
+       v[2] += s*v1[2];
+}
+
 
-static void softbody_calc_forces(Object *ob)
+static void softbody_calc_forces(Object *ob, float dtime)
 {
        SoftBody *sb= ob->soft; // is supposed to be there
-       BodyPoint *bp;
-       float ks;
-       int a;
-       
+       BodyPoint  *bp;
+       float iks,ks,kd,gravity,actspringlen,forcefactor,sd[3];
+       int a,b;
+       BodyPoint *bproot;
+       BodySpring *bs; 
        /* clear forces */
        for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
                bp->force[0]= bp->force[1]= bp->force[2]= 0.0;
        }
-               
-       /* spring constant */
-       ks= ob->springf;
-
-       /* accumulate forces, vertex stiffness */
+       
+       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 */
+       bproot= sb->bpoint; /* need this for proper spring addressing */
+       
        for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
-
-               bp->force[0]= ks*(bp->orig[0]-bp->pos[0]);
-               bp->force[1]= ks*(bp->orig[1]-bp->pos[1]);
-               bp->force[2]= ks*(bp->orig[2]-bp->pos[2]);
+               if(bp->goal < SOFTGOALSNAP){ // ommit this bp when i snaps
+                       float auxvect[3]; // aux unit vector  
+                       float velgoal[3];
+                       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]);
+                       }
+                       /* done goal stuff */
+                       
+                       
+                       /* gravitation */
+                       bp->force[2]-= gravity*ob->sb_nodemass; /* individual mass of node here */
+                       
+                       /* friction in media */
+                       kd= ob->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;
+                       bp->force[2]-= bp->vec[2]*kd;
+                       /* friction in media done */
+
+                       /*other forces*/
+                       /* this is the place where other forces can be added
+                       yes, constraints and collision stuff should go here too (read baraff papers on that!)
+                       */
+                       /*other forces done*/
+
+                       /* nice things could be done with anisotropic friction
+                       like wind/air resistance in normal direction
+                       --> having a piece of cloth sailing down 
+                       but this needs to have a *valid* vertex normal
+                       *valid* means to be calulated on time axis
+                       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 (( (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);                                                       
+                                               }
+                                       }
+                               } //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
+               }       
        }
 }
 
-static void softbody_apply_forces(Object *ob, float dtime)
+static void softbody_apply_forces(Object *ob, float dtime, int mode, float *err)
 {
+       /* time evolution */
+       /* actually does an explicit euler step mode == 0 */
+       /* or heun ~ 2nd order runge-kutta steps, mode 1,2 */
        SoftBody *sb= ob->soft; // is supposed to be there
        BodyPoint *bp;
-       float kd;
+       float dx[3],dv[3];
        int a;
+       float timeovermass;
+       float maxerr = 0.0;
        
-       kd= 1.0-ob->damping;
+       if (ob->sb_nodemass > 0.09999f) timeovermass = dtime/ob->sb_nodemass;
+       else timeovermass = dtime/0.09999f;
        
        for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
-               // friction
-               bp->vec[0]*= kd;
-               bp->vec[1]*= kd;
-               bp->vec[2]*= kd;
-               
-               VECADD(bp->vec, bp->vec, bp->force);    // mass here!?
-               VECADD(bp->pos, bp->pos, bp->vec);
+               if(bp->goal < SOFTGOALSNAP){
+                       
+                       /* so here is dv/dt = a = sum(F_springs)/m + gravitation + some friction forces */
+                       /* the euler step for velocity then becomes */
+                       /* v(t + dt) = v(t) + a(t) * dt */ 
+                       bp->force[0]*= timeovermass; /* individual mass of node here */ 
+                       bp->force[1]*= timeovermass;
+                       bp->force[2]*= timeovermass;
+                       /* 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);
+                       }
+                       if (mode ==2){
+                               /* be optimistic and execute step */
+                               bp->vec[0] = bp->prevvec[0] + 0.5f * (dv[0] + bp->prevdv[0]);
+                               bp->vec[1] = bp->prevvec[1] + 0.5f * (dv[1] + bp->prevdv[1]);
+                               bp->vec[2] = bp->prevvec[2] + 0.5f * (dv[2] + bp->prevdv[2]);
+                               /* compare euler to heun to estimate error for step sizing */
+                               maxerr = MAX2(maxerr,ABS(dv[0] - bp->prevdv[0]));
+                               maxerr = MAX2(maxerr,ABS(dv[1] - bp->prevdv[1]));
+                               maxerr = MAX2(maxerr,ABS(dv[2] - bp->prevdv[2]));
+                       }
+                       else {VECADD(bp->vec, bp->vec, bp->force);}
+
+                       /* so here is dx/dt = v */
+                       /* the euler step for location then becomes */
+                       /* x(t + dt) = x(t) + v(t) * dt */ 
+                       
+                       VECCOPY(dx,bp->vec);
+                       dx[0]*=dtime ; 
+                       dx[1]*=dtime ; 
+                       dx[2]*=dtime ; 
+                       
+                       /* again some nasty if's to have heun in here too */
+                       if (mode ==1){
+                               VECCOPY(bp->prevpos,bp->pos);
+                               VECCOPY(bp->prevdx ,dx);
+                       }
+                       
+                       if (mode ==2){
+                               bp->pos[0] = bp->prevpos[0] + 0.5f * ( dx[0] + bp->prevdx[0]);
+                               bp->pos[1] = bp->prevpos[1] + 0.5f * ( dx[1] + bp->prevdx[1]);
+                               bp->pos[2] = bp->prevpos[2] + 0.5f* ( dx[2] + bp->prevdx[2]);
+                               maxerr = MAX2(maxerr,ABS(dx[0] - bp->prevdx[0]));
+                               maxerr = MAX2(maxerr,ABS(dx[1] - bp->prevdx[1]));
+                               maxerr = MAX2(maxerr,ABS(dx[2] - bp->prevdx[2]));
+                       }
+                       else { VECADD(bp->pos, bp->pos, dx);}
+                       
+               }//snap
+       } //for
+       if (err){ /* so step size will be controlled by biggest difference in slope */
+               *err = maxerr;
        }
 }
 
+/* used by heun when it overshoots */
+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 */
 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;
+               ks= bp->goal*dtime;
                // this is hackish, screws up physics but stabilizes
-               vec[0]= ks*(bp->orig[0]-bp->pos[0]);
-               vec[1]= ks*(bp->orig[1]-bp->pos[1]);
-               vec[2]= ks*(bp->orig[2]-bp->pos[2]);
+               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.0-ks;
+               ks= 1.0f-ks;
                bp->vec[0]*= ks;
                bp->vec[1]*= ks;
                bp->vec[2]*= ks;
+               
+       }
+}
+
+static void softbody_apply_goalsnap(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++) {
+               if (bp->goal >= SOFTGOALSNAP){
+                       VECCOPY(bp->prevpos,bp->pos);
+                       VECCOPY(bp->pos,bp->origT);
+               }               
+       }
+}
+
+static void softbody_force_goal(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->pos,bp->origT);
+               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];               
        }
 }
 
+static void interpolate_exciter(Object *ob, int timescale, int time)
+{
+       Mesh *me= ob->data;
+       //MEdge *medge= me->medge;
+       int a;
+       BodyPoint *bp;
+       float f;
+       
+       if(ob->soft) {
+               f = (float)time/(float)timescale;
+               bp= ob->soft->bpoint;
+               for(a=0; a<me->totvert; 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];
+                       }
+               }
+               /* hrms .. do springs alter their lenght ?
+               if(medge) {
+               bs= ob->soft->bspring;
+               bp= ob->soft->bpoint;
+               for(a=0; (a<me->totedge && a < ob->soft->totspring ); a++, medge++, bs++) {
+               bs->len= VecLenf( (bp+bs->v1)->origT, (bp+bs->v2)->origT);
+               }
+               }
+               */
+       }       
+}
+
 
 /* ************ convertors ********** */
 
@@ -157,27 +584,60 @@ static void mesh_update_softbody(Object *ob)
        MVert *mvert= me->mvert;
        MEdge *medge= me->medge;
        BodyPoint *bp;
-       BodySpring *bs;
        int a;
-       
        if(ob->soft) {
        
                bp= ob->soft->bpoint;
                for(a=0; a<me->totvert; a++, mvert++, bp++) {
-                       VECCOPY(bp->orig, mvert->co);
-                       Mat4MulVecfl(ob->obmat, bp->orig);
+                       VECCOPY(bp->origS, bp->origE);
+                       VECCOPY(bp->origE, mvert->co);
+                       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; a<me->totedge; a++, medge++, bs++) {
-                               bs->len= VecLenf( (bp+bs->v1)->orig, (bp+bs->v2)->orig);
+                       for(a=0; (a<me->totedge && 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)
+/* 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;
+       locGroup=get_named_vertexgroup (ob,name);
+       if(locGroup){
+               /* retrieve index for that group */
+               groupindex =  get_defgroup_num (ob,locGroup); 
+               /* spot the vert in deform vert list at mesh */
+               /* todo (coder paranoya) what if ob->data is not a mesh .. */ 
+               /* hrms.. would like to have the same for lattices anyhoo */
+               dv = ((Mesh*)ob->data)->dvert + vertID;                         
+               /* Lets see if this vert is in the weight group */
+               for (i=0; i<dv->totweight; i++){
+                       if (dv->dw[i].def_nr == groupindex){
+                               *target=dv->dw[i].weight; /* got it ! */
+                               return 0;
+                       }
+               }/*for*/
+               return 2;
+       }/*if(locGroup)*/
+       return 1;
+} 
+
 /* makes totally fresh start situation */
 static void mesh_to_softbody(Object *ob)
 {
@@ -195,11 +655,44 @@ static void mesh_to_softbody(Object *ob)
                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->orig, bp->pos);
+                       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;
+*/
+
+
+
+                       } /* switch to vg scalars */
                }
+
+
+
                if(medge) {
                        bs= ob->soft->bspring;
                        bp= ob->soft->bpoint;
@@ -207,10 +700,20 @@ static void mesh_to_softbody(Object *ob)
                                bs->v1= medge->v1;
                                bs->v2= medge->v2;
                                bs->strength= 1.0;
-                               bs->len= VecLenf( (bp+bs->v1)->orig, (bp+bs->v2)->orig);
+                               bs->len= VecLenf( (bp+bs->v1)->origS, (bp+bs->v2)->origS);
                        }
                }
+               
+               /* insert *diagonal* springs in quads if desired */
+               if (ob->softflag & 0x02) {
+                add_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) {
@@ -234,6 +737,7 @@ static void mesh_to_softbody(Object *ob)
                                }
                        }
                }
+               */
                bp= ob->soft->bpoint;
                for(a=me->totvert; a>0; a--, bp++) {
                        //printf("a %d goal %f\n", a, bp->goal);
@@ -292,7 +796,7 @@ void object_update_softbody(Object *ob)
 }
 
 /* makes totally fresh start situation */
-void object_to_softbody(Object *ob)
+void object_to_softbody(Object *ob,float ctime)
 {
        
        if(ob->soft) free_softbody(ob->soft);
@@ -301,6 +805,7 @@ void object_to_softbody(Object *ob)
        switch(ob->type) {
        case OB_MESH:
                mesh_to_softbody(ob);
+               ob->soft->ctime = ctime;
                break;
        case OB_LATTICE:
                lattice_to_softbody(ob);
@@ -326,32 +831,165 @@ void softbody_to_object(Object *ob)
 
 
 /* simulates one step. ctime is in frames not seconds */
+
 void object_softbody_step(Object *ob, float ctime)
 {
        float dtime;
-       
+       int timescale,t;
+       float 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");
+               return;
+       }
        
+    softbody_scale_time(steptime); // translate frames/sec and lenghts unit to SI system
        dtime= ctime - ob->soft->ctime;
-       dtime= ABS(dtime);
-       if(dtime > 0.0) {
-               /* desired vertex locations in oldloc */
+       // 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) { 
                object_update_softbody(ob);
+               if (ob->softflag & 0x04){
+                       /* 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
+
+                       forcetime = dtime; /* hope for integrating in one step */
+                       while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) )
+                       {
+                               if (ABS(dtime) > 3.0 ){
+                                       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);
+                               // crop new slope values to do averaged slope step
+                               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
+                                       softbody_restore_prev_step(ob);
+                                       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);
+                                       else 
+                                       forcetime = MAX2(dtime - timedone,newtime);
+                               }
+                               loops++;
+                       }
+                       // move snapped to final position
+                       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);
+               }
+               else
+        /* do brute force explicit euler */
+               /* inner intagration loop */
+               /* */
+               // loop n times so that n*h = duration of one frame := 1
+               // x(t+h) = x(t) + h*v(t);
+               // v(t+h) = v(t) + h*f(x(t),t);
+               for(t=1 ; t <= timescale; t++) {
+                       if (ABS(dtime) > 15 ) break;
+                       
+                       /* 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);
                
-               /* extra for desired vertex locations */
-               softbody_apply_goal(ob, dtime);
-               
-               softbody_calc_forces(ob);
-               softbody_apply_forces(ob, dtime);
 
+//                     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);
+                softbody_to_object(ob);
                
                ob->soft->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);
        }
 }
 
index 9bbc63f729d858c500fb3de94147843c02c3e8b4..b93bd51904af4c228f349eb48fd5b7fabd471644 100644 (file)
@@ -451,6 +451,19 @@ enum {
 #define B_SHOWTEX              2832
 #define B_ASSIGNMESH   2833
 
+#define B_WEIGHT0_0        2840
+#define B_WEIGHT1_4        2841
+#define B_WEIGHT1_2        2842
+#define B_WEIGHT3_4        2843
+#define B_WEIGHT1_0        2844
+
+#define B_OPA0_0           2845
+#define B_OPA1_4           2846
+#define B_OPA1_2           2847
+#define B_OPA3_4           2848
+#define B_OPA1_0           2849
+
+
 
 /* *********************** */
 #define B_RADIOBUTS            3000
index da056ee35cd5f763970b0c61bf28d7a3e8931370..8c52da30bc03ff53b0a2cf186a93434773bbb83e 100644 (file)
@@ -150,7 +150,7 @@ typedef struct Object {
         * For a Sphere, the form factor is by default = 0.4
         */
 
-       float formfactor, springf;              /* springf temp for softbody */
+       float formfactor, softtime;             /* springf temp for softbody */
        float rdamping, sizefac;
        
        char dt, dtx;
@@ -186,7 +186,7 @@ typedef struct Object {
         * bit 15: Always ignore activity culling 
         */
        int gameflag2;
-       short softflag, pad;                    /* temporal stuff softbody experiment */
+       short softflag, dummy;                  /* temporal stuff softbody experiment */
        float anisotropicFriction[3];
 
        ListBase constraints;
@@ -201,6 +201,20 @@ typedef struct Object {
        LBuf port;
 
        float toonedge, smoothresh;     /* smoothresh is phong interpolation ray_shadow correction in render */
+/* this stuff MUST NOT be here
+   is here for softbody devel purpose 
+*/
+       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 */
+    
 } Object;
 
 typedef struct ObHook {
index 9f63557bda009b857b44eec9a444eab2f82b853c..3b3d272b18d8899ffba0dad6321066b69c5513cd 100644 (file)
@@ -1399,7 +1399,8 @@ void RE_animrender(struct View3D *ogl_render_view3d)
                }
                start_avi();
        }
-
+// set initial conditions for softbodies here
+// ******************************************
        for((G.scene->r.cfra)=(G.scene->r.sfra); (G.scene->r.cfra)<=(G.scene->r.efra); (G.scene->r.cfra)++) {
                double starttime= PIL_check_seconds_timer();
 
index 3ca9343143503d80fd119cf3f5dde56c6a78ffc8..094c11b9c00193cfe9a3b05bdf343483daed494c 100644 (file)
@@ -2318,6 +2318,7 @@ void do_fpaintbuts(unsigned short event)
        Mesh *me;
        Object *ob;
        extern TFace *lasttface; /* caches info on tface bookkeeping ?*/
+       extern VPaint Gvp;         /* from vpaint */
 
        ob= OBACT;
        if(ob==0) return;
@@ -2401,6 +2402,50 @@ void do_fpaintbuts(unsigned short event)
                        allqueue(REDRAWBUTSEDIT, 0);
                }
                break;
+       case B_WEIGHT0_0:
+               editbutvweight = 0.0f;
+               allqueue(REDRAWBUTSEDIT, 0);
+               break;
+
+       case B_WEIGHT1_4:
+               editbutvweight = 0.25f;
+               allqueue(REDRAWBUTSEDIT, 0);
+               break;
+       case B_WEIGHT1_2:
+               editbutvweight = 0.5f;
+               allqueue(REDRAWBUTSEDIT, 0);
+               break;
+       case B_WEIGHT3_4:
+               editbutvweight = 0.75f;
+               allqueue(REDRAWBUTSEDIT, 0);
+               break;
+       case B_WEIGHT1_0:
+               editbutvweight = 1.0f;
+               allqueue(REDRAWBUTSEDIT, 0);
+               break;
+               
+       case B_OPA0_0:
+               Gvp.a = 0.0f;
+               allqueue(REDRAWBUTSEDIT, 0);
+               break;
+       case B_OPA1_4:
+               Gvp.a = 0.25f;
+               allqueue(REDRAWBUTSEDIT, 0);
+               break;
+       case B_OPA1_2:
+               Gvp.a = 0.5f;
+               allqueue(REDRAWBUTSEDIT, 0);
+               break;
+       case B_OPA3_4:
+               Gvp.a = 0.75f;
+               allqueue(REDRAWBUTSEDIT, 0);
+               break;
+       case B_OPA1_0:
+               Gvp.a = 1.0f;
+               allqueue(REDRAWBUTSEDIT, 0);
+               break;
+               
+
        }
 }
 
@@ -2411,40 +2456,70 @@ static void editing_panel_mesh_paint(void)
 {
        extern VPaint Gvp;         /* from vpaint */
        uiBlock *block;
-
+       
        block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_paint", UI_EMBOSS, UI_HELV, curarea->win);
        if(uiNewPanel(curarea, block, "Paint", "Editing", 640, 0, 318, 204)==0) return;
+       
+       
+       if(G.f & ( G_WEIGHTPAINT))
+       {
+               Object *ob;
+           ob= OBACT;
+       if(ob==NULL) return;
 
-    uiBlockBeginAlign(block);
-       uiDefButF(block, NUMSLI, 0, "R ",                       979,160,194,19, &Gvp.r, 0.0, 1.0, B_VPCOLSLI, 0, "The amount of red used for painting");
-       uiDefButF(block, NUMSLI, 0, "G ",                       979,140,194,19, &Gvp.g, 0.0, 1.0, B_VPCOLSLI, 0, "The amount of green used for painting");
-       uiDefButF(block, NUMSLI, 0, "B ",                       979,120,194,19, &Gvp.b, 0.0, 1.0, B_VPCOLSLI, 0, "The amount of blue used for painting");
-       uiBlockEndAlign(block);
-
-       uiDefButF(block, NUMSLI, 0, "Opacity ",         979,100,194,19, &Gvp.a, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
-       uiDefButF(block, NUMSLI, 0, "Size ",            979,80,194,19, &Gvp.size, 2.0, 64.0, 0, 0, "The size of the brush");
-
-       uiDefButF(block, COL, B_REDR, "",               1176,99,28,80, &(Gvp.r), 0, 0, 0, B_VPCOLSLI, "");
-       uiBlockBeginAlign(block);
-       uiDefButS(block, ROW, B_DIFF, "Mix",                    1212,160,63,19, &Gvp.mode, 1.0, 0.0, 0, 0, "Mix the vertex colours");
-       uiDefButS(block, ROW, B_DIFF, "Add",                    1212,140,63,19, &Gvp.mode, 1.0, 1.0, 0, 0, "Add the vertex colour");
-       uiDefButS(block, ROW, B_DIFF, "Sub",                    1212, 120,63,19, &Gvp.mode, 1.0, 2.0, 0, 0, "Subtract from the vertex colour");
-       uiDefButS(block, ROW, B_DIFF, "Mul",                    1212, 100,63,19, &Gvp.mode, 1.0, 3.0, 0, 0, "Multiply the vertex colour");
-       uiDefButS(block, ROW, B_DIFF, "Filter",         1212, 80,63,19, &Gvp.mode, 1.0, 4.0, 0, 0, "Mix the colours with an alpha factor");
-
-       uiBlockBeginAlign(block);
-       uiDefButS(block, TOG|BIT|1, 0, "Area",          979,50,81,19, &Gvp.flag, 0, 0, 0, 0, "Vertex paint evaluates the area of the face the brush covers (otherwise vertices only)");
-       uiDefButS(block, TOG|BIT|2, 0, "Soft",          1061,50,112,19, &Gvp.flag, 0, 0, 0, 0, "Use a soft brush");
-       uiDefButS(block, TOG|BIT|3, 0, "Normals",       1174,50,102,19, &Gvp.flag, 0, 0, 0, 0, "Vertex paint applies the vertex normal before painting");
-
-       uiBlockBeginAlign(block);
-       uiDefBut(block, BUT, B_VPGAMMA, "Set",  979,30,81,19, 0, 0, 0, 0, 0, "Apply Mul and Gamma to vertex colours");
-       uiDefButF(block, NUM, B_DIFF, "Mul:",           1061,30,112,19, &Gvp.mul, 0.1, 50.0, 10, 0, "Set the number to multiply vertex colours with");
-       uiDefButF(block, NUM, B_DIFF, "Gamma:",         1174,30,102,19, &Gvp.gamma, 0.1, 5.0, 10, 0, "Change the clarity of the vertex colours");
-       uiBlockEndAlign(block);
-
-       uiDefBut(block, BUT, B_SET_VCOL, "Set VertCol", 979,5,81,20, 0, 0, 0, 0, 0, "Set Vertex colour of selection to current (Shift+K)");
-
+               uiBlockBeginAlign(block);
+               uiDefButF(block, NUMSLI, REDRAWVIEW3D, "Weight:",979,160,194,19, &editbutvweight, 0, 1, 10, 0, "Sets the current vertex group's bone deformation strength");
+               uiDefBut(block, BUT, B_WEIGHT0_0 , "0",                 979,140,40,19, 0, 0, 0, 0, 0, "");
+               uiDefBut(block, BUT, B_WEIGHT1_4 , "1/4",                       1020,140,40,19, 0, 0, 0, 0, 0, "");
+               uiDefBut(block, BUT, B_WEIGHT1_2 , "1/2",                       1060,140,40,19, 0, 0, 0, 0, 0, "");
+               uiDefBut(block, BUT, B_WEIGHT3_4 , "3/4",                       1100,140,40,19, 0, 0, 0, 0, 0, "");
+               uiDefBut(block, BUT, B_WEIGHT1_0 , "1",                 1140,140,33,19, 0, 0, 0, 0, 0, "");
+               
+               uiDefButF(block, NUMSLI, 0, "Opacity ",         979,120,194,19, &Gvp.a, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
+               uiDefBut(block, BUT, B_OPA0_0 , "0",                    979,100,40,19, 0, 0, 0, 0, 0, "");
+               uiDefBut(block, BUT, B_OPA1_4 , "1/4",                  1020,100,40,19, 0, 0, 0, 0, 0, "");
+               uiDefBut(block, BUT, B_OPA1_2 , "1/2",                  1060,100,40,19, 0, 0, 0, 0, 0, "");
+               uiDefBut(block, BUT, B_OPA3_4 , "3/4",                  1100,100,40,19, 0, 0, 0, 0, 0, "");
+               uiDefBut(block, BUT, B_OPA1_0 , "1",                    1140,100,33,19, 0, 0, 0, 0, 0, "");
+               uiDefButF(block, NUMSLI, 0, "Size ",            979,80,194,19, &Gvp.size, 2.0, 64.0, 0, 0, "The size of the brush");
+               uiBlockEndAlign(block);
+               if(ob){
+               uiBlockBeginAlign(block);
+       uiDefButBitC(block, TOG, OB_DRAWWIRE, REDRAWVIEW3D, "Wire",     979,40,194,19   , &ob->dtx, 0, 0, 0, 0, "Displays the active object's wireframe in shaded drawing modes");
+               uiBlockEndAlign(block);
+               }
+       }
+       else{
+               uiBlockBeginAlign(block);
+               uiDefButF(block, NUMSLI, 0, "R ",                       979,160,194,19, &Gvp.r, 0.0, 1.0, B_VPCOLSLI, 0, "The amount of red used for painting");
+               uiDefButF(block, NUMSLI, 0, "G ",                       979,140,194,19, &Gvp.g, 0.0, 1.0, B_VPCOLSLI, 0, "The amount of green used for painting");
+               uiDefButF(block, NUMSLI, 0, "B ",                       979,120,194,19, &Gvp.b, 0.0, 1.0, B_VPCOLSLI, 0, "The amount of blue used for painting");
+               uiBlockEndAlign(block);
+               uiDefButF(block, NUMSLI, 0, "Opacity ",         979,100,194,19, &Gvp.a, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
+               uiDefButF(block, NUMSLI, 0, "Size ",            979,80,194,19, &Gvp.size, 2.0, 64.0, 0, 0, "The size of the brush");
+               
+               uiDefButF(block, COL, B_REDR, "",               1176,99,28,80, &(Gvp.r), 0, 0, 0, B_VPCOLSLI, "");
+               uiBlockBeginAlign(block);
+               uiDefButS(block, ROW, B_DIFF, "Mix",                    1212,160,63,19, &Gvp.mode, 1.0, 0.0, 0, 0, "Mix the vertex colours");
+               uiDefButS(block, ROW, B_DIFF, "Add",                    1212,140,63,19, &Gvp.mode, 1.0, 1.0, 0, 0, "Add the vertex colour");
+               uiDefButS(block, ROW, B_DIFF, "Sub",                    1212, 120,63,19, &Gvp.mode, 1.0, 2.0, 0, 0, "Subtract from the vertex colour");
+               uiDefButS(block, ROW, B_DIFF, "Mul",                    1212, 100,63,19, &Gvp.mode, 1.0, 3.0, 0, 0, "Multiply the vertex colour");
+               uiDefButS(block, ROW, B_DIFF, "Filter",         1212, 80,63,19, &Gvp.mode, 1.0, 4.0, 0, 0, "Mix the colours with an alpha factor");
+               
+               uiBlockBeginAlign(block);
+               uiDefButS(block, TOG|BIT|1, 0, "Area",          979,50,81,19, &Gvp.flag, 0, 0, 0, 0, "Vertex paint evaluates the area of the face the brush covers (otherwise vertices only)");
+               uiDefButS(block, TOG|BIT|2, 0, "Soft",          1061,50,112,19, &Gvp.flag, 0, 0, 0, 0, "Use a soft brush");
+               uiDefButS(block, TOG|BIT|3, 0, "Normals",       1174,50,102,19, &Gvp.flag, 0, 0, 0, 0, "Vertex paint applies the vertex normal before painting");
+               
+               uiBlockBeginAlign(block);
+               uiDefBut(block, BUT, B_VPGAMMA, "Set",  979,30,81,19, 0, 0, 0, 0, 0, "Apply Mul and Gamma to vertex colours");
+               uiDefButF(block, NUM, B_DIFF, "Mul:",           1061,30,112,19, &Gvp.mul, 0.1, 50.0, 10, 0, "Set the number to multiply vertex colours with");
+               uiDefButF(block, NUM, B_DIFF, "Gamma:",         1174,30,102,19, &Gvp.gamma, 0.1, 5.0, 10, 0, "Change the clarity of the vertex colours");
+               uiBlockEndAlign(block);
+               
+               uiDefBut(block, BUT, B_SET_VCOL, "Set VertCol", 979,5,81,20, 0, 0, 0, 0, 0, "Set Vertex colour of selection to current (Shift+K)");
+       }
+       
 }
 
 static void editing_panel_mesh_texface(void)
index 87e9fdba955117068d7b410a215bbbf21dad65b6..716a3f448bc105eeb37d10837467255326a97007 100644 (file)
@@ -1434,12 +1434,72 @@ static void object_panel_deflectors(Object *ob)
                }
                uiBlockEndAlign(block);
        }
-
+/*
        if(strncmp(ob->id.name+2, "soft", 4)==0) {
-               uiDefButS(block, TOG|BIT|0, B_DIFF, "Soft Body",        220,160,200,20, &ob->softflag, 0, 0, 0, 0, "Sets object to become soft body");
-               uiDefButF(block, NUM, B_DIFF, "Spring: ",                       220,140,200,20, &ob->springf, 0.0, 1.0, 10, 0, "Spring constant");
-               uiDefButF(block, NUM, B_DIFF, "Damp: ",                         220,120,200,20, &ob->damping, 0.0, 1.0, 10, 0, "General damping in softbody on point movements");
+               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 */
+
+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;
+
+       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");
+               
+               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);
+
 }
 
 void object_panel_effects(Object *ob)
@@ -1451,7 +1511,7 @@ void object_panel_effects(Object *ob)
        
        block= uiNewBlock(&curarea->uiblocks, "object_panel_effects", UI_EMBOSS, UI_HELV, curarea->win);
        uiNewPanelTabbed("Constraints", "Object");
-       if(uiNewPanel(curarea, block, "Effects", "Object", 640, 0, 418, 204)==0) return;
+       if(uiNewPanel(curarea, block, "Effects", "Object", 640, 0, 318, 204)==0) return;
 
        /* EFFECTS */
        
@@ -1604,6 +1664,7 @@ void object_panels()
                        object_panel_effects(ob);
                }
                object_panel_deflectors(ob);
+               object_softbodies(ob);
 
                uiClearButLock();
        }
index b366ea188b835f278478e1ba046b6a05099ea4aa..6b4b837a6e7c8a1091b94752eed932f2e125070a 100644 (file)
@@ -4322,7 +4322,7 @@ void draw_object(Base *base)
                        if(ob->parent && ob->partype==PARSKEL) makeDispList(ob);
                        else if(ob->parent && ob->parent->type==OB_LATTICE) makeDispList(ob);
                        else if(ob->hooks.first) makeDispList(ob);
-                       else if(ob->softflag) makeDispList(ob);
+                       else if(ob->softflag & 0x01) makeDispList(ob);
                        else if(me->disp.first==NULL && mesh_uses_displist(me)) makeDispList(ob);
                        else if(ob->effect.first) {     // as last check
                                Effect *eff= ob->effect.first;
index 2401df87f693962d4742b4d14380dca82c8a7e1d..31f883fafe5f6d71a00552b4b0a3bc8f74b31027 100644 (file)
@@ -1063,6 +1063,54 @@ void fill_mesh(void)
 /* ******************** SUBDIVIDE ********************************** */
 
 
+static void merge_weights(EditVert * vt, EditVert *vs )
+{
+       MDeformWeight *newdw;
+       int i,j,done;
+       for (j=0; j<vs->totweight; j++){
+               done=0;
+               /* Is vertex memeber of group */
+               /* If so: Change its weight */
+               for (i=0; i<vt->totweight; i++){
+                       if (vt->dw[i].def_nr == vs->dw[j].def_nr)
+                       {   /* taking the maximum makes it independant from order of occurance */
+                               if (vt->dw[i].weight < vs->dw[j].weight) vt->dw[i].weight = vs->dw[j].weight;
+                               done=1;
+                               break;
+                       }
+               }
+               /* If not: Add the group and set its weight */
+               if (!done){
+                       newdw = MEM_callocN (sizeof(MDeformWeight)*(vt->totweight+1), "deformWeight");
+                       if (vt->dw){
+                               memcpy (newdw, vt->dw, sizeof(MDeformWeight)*vt->totweight);
+                               MEM_freeN (vt->dw);
+                       }
+                       vt->dw=newdw;
+                       vt->dw[vt->totweight].weight=vs->dw[j].weight;
+                       vt->dw[vt->totweight].def_nr=vs->dw[j].def_nr;
+                       vt->totweight++;
+               }
+       }
+}
+
+
+static void set_weights(EditVert * vt, EditVert *vs1,EditVert *vs2,EditVert *vs3,EditVert *vs4 )
+{
+/*
+vt is a new generated vertex with empty deform group information
+vs1..v4 are egde neighbours holding group information
+so let the information ooze into the new one
+*/
+       if (vs1) merge_weights(vt,vs1);
+       if (vs2) merge_weights(vt,vs2);
+       if (vs3) merge_weights(vt,vs3);
+       if (vs4) merge_weights(vt,vs4);
+}
+
+
+
+
 static unsigned int cpack_fact(unsigned int col1, unsigned int col2, float fact)
 {
        char *cp1, *cp2, *cp;
@@ -1105,6 +1153,9 @@ static void face_pin_vertex(EditFace *efa, EditVert *vertex)
        else if(efa->v4 && vertex && efa->v4 == vertex) efa->tf.unwrap |= TF_PIN4;
 }
 
+
+
+
 static void set_wuv(int tot, EditFace *efa, int v1, int v2, int v3, int v4, EditFace *efapin)
 {
        /* this weird function only to be used for subdivide, the 'w' in the name has no meaning! */
@@ -1486,6 +1537,7 @@ void subdivideflag(int flag, float rad, int beauty)
                                /* add edges here, to copy correct edge data */
                                eed= addedgelist(e1->v1, e1->vn, e1);
                                eed= addedgelist(e1->vn, e1->v2, e1);
+                               set_weights(e1->vn, e1->v1,e1->v2,NULL,NULL);
                        }
                        if(e2 && e2->vn) {
                                test+= 2;
@@ -1493,6 +1545,7 @@ void subdivideflag(int flag, float rad, int beauty)
                                /* add edges here, to copy correct edge data */
                                eed= addedgelist(e2->v1, e2->vn, e2);
                                eed= addedgelist(e2->vn, e2->v2, e2);
+                               set_weights(e2->vn, e2->v1,e2->v2,NULL,NULL);
                        }
                        if(e3 && e3->vn) {
                                test+= 4;
@@ -1500,6 +1553,7 @@ void subdivideflag(int flag, float rad, int beauty)
                                /* add edges here, to copy correct edge data */
                                eed= addedgelist(e3->v1, e3->vn, e3);
                                eed= addedgelist(e3->vn, e3->v2, e3);
+                               set_weights(e3->vn, e3->v1,e3->v2,NULL,NULL);
                        }
                        if(e4 && e4->vn) {
                                test+= 8;
@@ -1507,6 +1561,7 @@ void subdivideflag(int flag, float rad, int beauty)
                                /* add edges here, to copy correct edge data */
                                eed= addedgelist(e4->v1, e4->vn, e4);
                                eed= addedgelist(e4->vn, e4->v2, e4);
+                               set_weights(e4->vn, e4->v1,e4->v2,NULL,NULL);
                        }
                        if(test) {
                                if(efa->v4==0) {  /* All the permutations of 3 edges*/
@@ -1564,7 +1619,7 @@ void subdivideflag(int flag, float rad, int beauty)
                                                        smooth_subdiv_quad(efa, vec);   /* adds */
                                                }
                                                eve= addvertlist(vec);
-                                               
+                                               set_weights(eve, efa->v1,efa->v2,efa->v3,efa->v4);
                                                eve->f |= flag;
 
                                                addface_subdiv(efa, 2, 2+4, 9, 1+4, eve, &efapin);
@@ -1621,6 +1676,7 @@ void subdivideflag(int flag, float rad, int beauty)
                                                        vec[1]=(e1->vn->co[1]+e2->vn->co[1])/2;
                                                        vec[2]=(e1->vn->co[2]+e2->vn->co[2])/2;
                                                        eve= addvertlist(vec);
+                                                       set_weights(eve, e1->vn,e2->vn,NULL,NULL);
                                                        eve->f |= flag;
                                                        /* Add new faces */
                                                        addface_subdiv(efa, 4, 10, 2+4, 3, eve, &efapin);
@@ -1639,6 +1695,7 @@ void subdivideflag(int flag, float rad, int beauty)
                                                        vec[1]=(e2->vn->co[1]+e3->vn->co[1])/2;
                                                        vec[2]=(e2->vn->co[2]+e3->vn->co[2])/2;
                                                        eve= addvertlist(vec);
+                                                       set_weights(eve, e2->vn,e3->vn,NULL,NULL);
                                                        eve->f |= flag;
                                                        /*New faces*/
                                                        addface_subdiv(efa, 1, 11, 3+4, 4, eve, &efapin);
@@ -1657,6 +1714,7 @@ void subdivideflag(int flag, float rad, int beauty)
                                                        vec[1]=(e3->vn->co[1]+e4->vn->co[1])/2;
                                                        vec[2]=(e3->vn->co[2]+e4->vn->co[2])/2;
                                                        eve= addvertlist(vec);
+                                                       set_weights(eve, e3->vn,e4->vn,NULL,NULL);
                                                        eve->f |= flag;
                                                        /*New Faces*/
                                                        addface_subdiv(efa, 2, 12, 4+4, 1, eve, &efapin);
@@ -1675,6 +1733,7 @@ void subdivideflag(int flag, float rad, int beauty)
                                                        vec[1]=(e1->vn->co[1]+e4->vn->co[1])/2;
                                                        vec[2]=(e1->vn->co[2]+e4->vn->co[2])/2;
                                                        eve= addvertlist(vec);
+                                                       set_weights(eve, e1->vn,e4->vn,NULL,NULL);
                                                        eve->f |= flag;
                                                        /*New Faces*/
                                                        addface_subdiv(efa, 3, 13, 1+4, 2, eve, &efapin);
index 343d979fcce490e8261a553a877cb06849e6d99c..65d2a4b38d78c6ebbd27560053a7312c87d376d6 100644 (file)
@@ -1526,6 +1526,15 @@ 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);
+       
        makeDispList(ob);
 
        /* has this influence at other objects? */
@@ -1563,8 +1572,8 @@ void exit_editmode(int freedata)  /* freedata==0 at render, 1= freedata, 2= do un
                allqueue(REDRAWOOPS, 0);
        }
        scrarea_queue_headredraw(curarea);
-
-       if(ob->softflag) object_to_softbody(ob);
+// faaaaar to late
+//     if(ob->softflag & 0x01) object_to_softbody(ob);
        
        if(G.obedit==NULL && freedata==2) 
                BIF_undo_push("Editmode");
index cfbd659a82290f84983343a3375c3b3af686520b..ca96f19a978e429e682b7876a35b1b22e9454188 100644 (file)
@@ -3919,6 +3919,7 @@ void view3d_buttons(void)
        uiBlockEndAlign(block);
        
        xco+= XIC+8;
+
        
        /* LAYERS */
        if(G.vd->localview==0) {
@@ -4002,6 +4003,11 @@ 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;