svn merge -r 16060:16222 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender-staging.git] / source / blender / blenkernel / intern / particle_system.c
index b399fdd61d227b26c88f47ade60c607ade72c98d..98bf817381904401d7fdff4e752c2c55a47405bc 100644 (file)
@@ -60,6 +60,7 @@
 #include "BKE_bad_level_calls.h"
 #include "BKE_cdderivedmesh.h"
 #include "BKE_displist.h"
+#include "BKE_effect.h"
 #include "BKE_particle.h"
 #include "BKE_global.h"
 #include "BKE_utildefines.h"
@@ -2208,174 +2209,6 @@ static int get_particles_from_cache(Object *ob, ParticleSystem *psys, int cfra)
 /************************************************/
 /*                     Effectors                                                       */
 /************************************************/
-static float falloff_func(float fac, int usemin, float mindist, int usemax, float maxdist, float power)
-{
-       if(!usemin)
-               mindist= 0.0f;
-
-       if(fac < mindist) {
-               return 1.0f;
-       }
-       else if(usemax) {
-               if(fac>maxdist || (maxdist-mindist)<=0.0f)
-                       return 0.0f;
-
-               fac= (fac-mindist)/(maxdist-mindist);
-               return 1.0f - (float)pow((double)fac, (double)power);
-       }
-       else
-               return pow((double)1.0f+fac-mindist, (double)-power);
-}
-
-static float falloff_func_dist(PartDeflect *pd, float fac)
-{
-       return falloff_func(fac, pd->flag&PFIELD_USEMIN, pd->mindist, pd->flag&PFIELD_USEMAX, pd->maxdist, pd->f_power);
-}
-
-static float falloff_func_rad(PartDeflect *pd, float fac)
-{
-       return falloff_func(fac, pd->flag&PFIELD_USEMINR, pd->minrad, pd->flag&PFIELD_USEMAXR, pd->maxrad, pd->f_power_r);
-}
-
-static float effector_falloff(PartDeflect *pd, float *eff_velocity, float *vec_to_part)
-{
-       float eff_dir[3], temp[3];
-       float falloff=1.0, fac, r_fac;
-       
-       VecCopyf(eff_dir,eff_velocity);
-       Normalize(eff_dir);
-
-       if(pd->flag & PFIELD_POSZ && Inpf(eff_dir,vec_to_part)<0.0f)
-               falloff=0.0f;
-       else switch(pd->falloff){
-               case PFIELD_FALL_SPHERE:
-                       fac=VecLength(vec_to_part);
-                       falloff= falloff_func_dist(pd, fac);
-                       break;
-
-               case PFIELD_FALL_TUBE:
-                       fac=Inpf(vec_to_part,eff_dir);
-                       falloff= falloff_func_dist(pd, ABS(fac));
-                       if(falloff == 0.0f)
-                               break;
-
-                       VECADDFAC(temp,vec_to_part,eff_dir,-fac);
-                       r_fac=VecLength(temp);
-                       falloff*= falloff_func_rad(pd, r_fac);
-                       break;
-               case PFIELD_FALL_CONE:
-                       fac=Inpf(vec_to_part,eff_dir);
-                       falloff= falloff_func_dist(pd, ABS(fac));
-                       if(falloff == 0.0f)
-                               break;
-
-                       r_fac=saacos(fac/VecLength(vec_to_part))*180.0f/(float)M_PI;
-                       falloff*= falloff_func_rad(pd, r_fac);
-
-                       break;
-//             case PFIELD_FALL_INSIDE:
-                               //for(i=0; i<totface; i++,mface++){
-                               //      VECCOPY(v1,mvert[mface->v1].co);
-                               //      VECCOPY(v2,mvert[mface->v2].co);
-                               //      VECCOPY(v3,mvert[mface->v3].co);
-
-                               //      if(AxialLineIntersectsTriangle(a,co1, co2, v2, v3, v1, &lambda)){
-                               //              if(from==PART_FROM_FACE)
-                               //                      (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
-                               //              else /* store number of intersections */
-                               //                      (pa+(int)(lambda*size[a])*a0mul)->loop++;
-                               //      }
-                               //      
-                               //      if(mface->v4){
-                               //              VECCOPY(v4,mvert[mface->v4].co);
-
-                               //              if(AxialLineIntersectsTriangle(a,co1, co2, v4, v1, v3, &lambda)){
-                               //                      if(from==PART_FROM_FACE)
-                               //                              (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
-                               //                      else
-                               //                              (pa+(int)(lambda*size[a])*a0mul)->loop++;
-                               //              }
-                               //      }
-                               //}
-
-//                     break;
-       }
-
-       return falloff;
-}
-static void do_physical_effector(short type, float force_val, float distance, float falloff, float size, float damp,
-                                                       float *eff_velocity, float *vec_to_part, float *velocity, float *field, int planar)
-{
-       float mag_vec[3]={0,0,0};
-       float temp[3], temp2[3];
-       float eff_vel[3];
-
-       VecCopyf(eff_vel,eff_velocity);
-       Normalize(eff_vel);
-
-       switch(type){
-               case PFIELD_WIND:
-                       VECCOPY(mag_vec,eff_vel);
-
-                       VecMulf(mag_vec,force_val*falloff);
-                       VecAddf(field,field,mag_vec);
-                       break;
-
-               case PFIELD_FORCE:
-                       if(planar)
-                               Projf(mag_vec,vec_to_part,eff_vel);
-                       else
-                               VecCopyf(mag_vec,vec_to_part);
-
-                       VecMulf(mag_vec,force_val*falloff);
-                       VecAddf(field,field,mag_vec);
-                       break;
-
-               case PFIELD_VORTEX:
-                       Crossf(mag_vec,eff_vel,vec_to_part);
-                       Normalize(mag_vec);
-
-                       VecMulf(mag_vec,force_val*distance*falloff);
-                       VecAddf(field,field,mag_vec);
-
-                       break;
-               case PFIELD_MAGNET:
-                       if(planar)
-                               VecCopyf(temp,eff_vel);
-                       else
-                               /* magnetic field of a moving charge */
-                               Crossf(temp,eff_vel,vec_to_part);
-
-                       Crossf(temp2,velocity,temp);
-                       VecAddf(mag_vec,mag_vec,temp2);
-
-                       VecMulf(mag_vec,force_val*falloff);
-                       VecAddf(field,field,mag_vec);
-                       break;
-               case PFIELD_HARMONIC:
-                       if(planar)
-                               Projf(mag_vec,vec_to_part,eff_vel);
-                       else
-                               VecCopyf(mag_vec,vec_to_part);
-
-                       VecMulf(mag_vec,force_val*falloff);
-                       VecSubf(field,field,mag_vec);
-
-                       VecCopyf(mag_vec,velocity);
-                       /* 1.9 is an experimental value to get critical damping at damp=1.0 */
-                       VecMulf(mag_vec,damp*1.9f*(float)sqrt(force_val));
-                       VecSubf(field,field,mag_vec);
-                       break;
-               case PFIELD_NUCLEAR:
-                       /*pow here is root of cosine expression below*/
-                       //rad=(float)pow(2.0,-1.0/power)*distance/size;
-                       //VECCOPY(mag_vec,vec_to_part);
-                       //Normalize(mag_vec);
-                       //VecMulf(mag_vec,(float)cos(3.0*M_PI/2.0*(1.0-1.0/(pow(rad,power)+1.0)))/(rad+0.2f));
-                       //VECADDFAC(field,field,mag_vec,force_val);
-                       break;
-       }
-}
 static void do_texture_effector(Tex *tex, short mode, short is_2d, float nabla, short object, float *pa_co, float obmat[4][4], float force_val, float falloff, float *field)
 {
        TexResult result[4];
@@ -2493,10 +2326,11 @@ static void add_to_effectors(ListBase *lb, Object *ob, Object *obsrc, ParticleSy
 
                for(i=0; epsys; epsys=epsys->next,i++){
                        type=0;
-                       if(epsys!=psys){
+                       if(epsys!=psys || (psys->part->flag & PART_SELF_EFFECT)){
                                epart=epsys->part;
 
-                               if(epsys->part->pd && epsys->part->pd->forcefield)
+                               if((epsys->part->pd && epsys->part->pd->forcefield)
+                                       || (epsys->part->pd2 && epsys->part->pd2->forcefield))
                                        type=PSYS_EC_PARTICLE;
 
                                if(epart->type==PART_REACTOR) {
@@ -2745,35 +2579,31 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P
        ListBase *lb=&psys->effectors;
        ParticleEffectorCache *ec;
        float distance, vec_to_part[3];
-       float falloff;
+       float falloff, charge = 0.0f;
        int p;
 
        /* check all effector objects for interaction */
        if(lb->first){
+               if(psys->part->pd && psys->part->pd->forcefield==PFIELD_CHARGE){
+                       /* Only the charge of the effected particle is used for 
+                          interaction, not fall-offs. If the fall-offs aren't the      
+                          same this will be unphysical, but for animation this         
+                          could be the wanted behavior. If you want physical
+                          correctness the fall-off should be spherical 2.0 anyways.
+                        */
+                       charge = psys->part->pd->f_strength;
+               }
+               if(psys->part->pd2 && psys->part->pd2->forcefield==PFIELD_CHARGE){
+                       charge += psys->part->pd2->f_strength;
+               }
                for(ec = lb->first; ec; ec= ec->next){
                        eob= ec->ob;
                        if(ec->type & PSYS_EC_EFFECTOR){
                                pd=eob->pd;
                                if(psys->part->type!=PART_HAIR && psys->part->integrator)
                                        where_is_object_time(eob,cfra);
-                               /* Get IPO force strength and fall off values here */
-                               //if (has_ipo_code(eob->ipo, OB_PD_FSTR))
-                               //      force_val = IPO_GetFloatValue(eob->ipo, OB_PD_FSTR, cfra);
-                               //else 
-                               //      force_val = pd->f_strength;
-                               
-                               //if (has_ipo_code(eob->ipo, OB_PD_FFALL)) 
-                               //      ffall_val = IPO_GetFloatValue(eob->ipo, OB_PD_FFALL, cfra);
-                               //else 
-                               //      ffall_val = pd->f_power;
-
-                               //if (has_ipo_code(eob->ipo, OB_PD_FMAXD)) 
-                               //      maxdist = IPO_GetFloatValue(eob->ipo, OB_PD_FMAXD, cfra);
-                               //else 
-                               //      maxdist = pd->maxdist;
 
                                /* use center of object for distance calculus */
-                               //obloc= eob->obmat[3];
                                VecSubf(vec_to_part, state->co, eob->obmat[3]);
                                distance = VecLength(vec_to_part);
 
@@ -2786,22 +2616,22 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P
                                                                        pd->flag & PFIELD_TEX_OBJECT, (pd->flag & PFIELD_TEX_ROOTCO) ? rootco : state->co, eob->obmat,
                                                                        pd->f_strength, falloff, force_field);
                                } else {
-                                       do_physical_effector(pd->forcefield,pd->f_strength,distance,
-                                                                               falloff,pd->f_dist,pd->f_damp,eob->obmat[2],vec_to_part,
-                                                                               pa->state.vel,force_field,pd->flag&PFIELD_PLANAR);
+                                       do_physical_effector(eob, state->co, pd->forcefield,pd->f_strength,distance,
+                                                                               falloff,0.0,pd->f_damp,eob->obmat[2],vec_to_part,
+                                                                               pa->state.vel,force_field,pd->flag&PFIELD_PLANAR,pd->rng,pd->f_noise,charge,pa->size);
                                }
                        }
                        if(ec->type & PSYS_EC_PARTICLE){
-                               int totepart;
+                               int totepart, i;
                                epsys= BLI_findlink(&eob->particlesystem,ec->psys_nbr);
                                epart= epsys->part;
-                               pd= epart->pd;
+                               pd=epart->pd;
                                totepart= epsys->totpart;
                                
                                if(totepart <= 0)
                                        continue;
                                
-                               if(pd->forcefield==PFIELD_HARMONIC){
+                               if(pd && pd->forcefield==PFIELD_HARMONIC){
                                        /* every particle is mapped to only one harmonic effector particle */
                                        p= pa_no%epsys->totpart;
                                        totepart= p+1;
@@ -2813,31 +2643,27 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P
                                epsys->lattice=psys_get_lattice(ob,psys);
 
                                for(; p<totepart; p++){
+                                       /* particle skips itself as effector */
+                                       if(epsys==psys && p == pa_no) continue;
+
                                        epa = epsys->particles + p;
                                        estate.time=-1.0;
                                        if(psys_get_particle_state(eob,epsys,p,&estate,0)){
                                                VECSUB(vec_to_part, state->co, estate.co);
                                                distance = VecLength(vec_to_part);
-
-                                               //if(pd->forcefield==PFIELD_HARMONIC){
-                                               //      //if(cfra < epa->time + radius){ /* radius is fade-in in ui */
-                                               //      //      eforce*=(cfra-epa->time)/radius;
-                                               //      //}
-                                               //}
-                                               //else{
-                                               //      /* Limit minimum distance to effector particle so that */
-                                               //      /* the force is not too big */
-                                               //      if (distance < 0.001) distance = 0.001f;
-                                               //}
                                                
-                                               falloff=effector_falloff(pd,estate.vel,vec_to_part);
+                                               for(i=0, pd = epart->pd; i<2; i++,pd = epart->pd2) {
+                                                       if(pd==NULL || pd->forcefield==0) continue;
 
-                                               if(falloff<=0.0f)
-                                                       ;       /* don't do anything */
-                                               else
-                                                       do_physical_effector(pd->forcefield,pd->f_strength,distance,
-                                                       falloff,epart->size,pd->f_damp,estate.vel,vec_to_part,
-                                                       state->vel,force_field,0);
+                                                       falloff=effector_falloff(pd,estate.vel,vec_to_part);
+
+                                                       if(falloff<=0.0f)
+                                                               ;       /* don't do anything */
+                                                       else
+                                                               do_physical_effector(eob, state->co, pd->forcefield,pd->f_strength,distance,
+                                                               falloff,epart->size,pd->f_damp,estate.vel,vec_to_part,
+                                                               state->vel,force_field,0, pd->rng, pd->f_noise,charge,pa->size);
+                                               }
                                        }
                                        else if(pd->forcefield==PFIELD_HARMONIC && cfra-framestep <= epa->dietime && cfra>epa->dietime){
                                                /* first step after key release */
@@ -3948,27 +3774,44 @@ static void boid_body(BoidVecFunc *bvf, ParticleData *pa, ParticleSystem *psys,
        bvf->Addf(dvec,dvec,bvec);
        bvf->Addf(state->co,state->co,dvec);
        
-       /* air speed from wind effectors */
-       if(psys->effectors.first){
+       /* air speed from wind and vortex effectors */
+       if(psys->effectors.first) {
                ParticleEffectorCache *ec;
-               for(ec=psys->effectors.first; ec; ec=ec->next){
-                       if(ec->type & PSYS_EC_EFFECTOR){
+               for(ec=psys->effectors.first; ec; ec=ec->next) {
+                       if(ec->type & PSYS_EC_EFFECTOR) {
                                Object *eob = ec->ob;
                                PartDeflect *pd = eob->pd;
+                               float direction[3], vec_to_part[3];
+                               float falloff;
+
+                               if(pd->f_strength != 0.0f) {
+                                       VecCopyf(direction, eob->obmat[2]);
+                                       VecSubf(vec_to_part, state->co, eob->obmat[3]);
+
+                                       falloff=effector_falloff(pd, direction, vec_to_part);
+
+                                       switch(pd->forcefield) {
+                                               case PFIELD_WIND:
+                                                       if(falloff <= 0.0f)
+                                                               ;       /* don't do anything */
+                                                       else {
+                                                               Normalize(direction);
+                                                               VecMulf(direction, pd->f_strength * falloff);
+                                                               bvf->Addf(state->co, state->co, direction);
+                                                       }
+                                                       break;
+                                               case PFIELD_VORTEX:
+                                               {
+                                                       float distance, mag_vec[3];
+                                                       Crossf(mag_vec, direction, vec_to_part);
+                                                       Normalize(mag_vec);
 
-                               if(pd->forcefield==PFIELD_WIND && pd->f_strength!=0.0){
-                                       float distance, wind[3];
-                                       VecCopyf(wind,eob->obmat[2]);
-                                       distance=VecLenf(state->co,eob->obmat[3]);
-
-                                       if (distance < 0.001) distance = 0.001f;
+                                                       distance = VecLength(vec_to_part);
 
-                                       if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist)
-                                               ;
-                                       else{
-                                               Normalize(wind);
-                                               VecMulf(wind,pd->f_strength/(float)pow((double)distance,(double)pd->f_power));
-                                               bvf->Addf(state->co,state->co,wind);
+                                                       VecMulf(mag_vec, pd->f_strength * distance * falloff);
+                                                       bvf->Addf(state->co, state->co, mag_vec);
+                                                       break;
+                                               }
                                        }
                                }
                        }