diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-11-13 00:16:53 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-11-13 00:16:53 +0300 |
commit | bdfe7d89e2f1292644577972c716931b4ce3c6c3 (patch) | |
tree | d00eb50b749cb001e2b08272c91791e66740b05d /source/blender/blenkernel/intern/effect.c | |
parent | 78a1c27c4a6abe0ed31ca93ad21910f3df04da56 (diff) | |
parent | 7e4db234cee71ead34ee81a12e27da4bd548eb4b (diff) |
Merge of trunk into blender 2.5:
svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r12987:17416
Issues:
* GHOST/X11 had conflicting changes. Some code was added in 2.5, which was
later added in trunk also, but reverted partially, specifically revision
16683. I have left out this reversion in the 2.5 branch since I think it is
needed there.
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16683
* Scons had various conflicting changes, I decided to go with trunk version
for everything except priorities and some library renaming.
* In creator.c, there were various fixes and fixes for fixes related to the -w
-W and -p options. In 2.5 -w and -W is not coded yet, and -p is done
differently. Since this is changed so much, and I don't think those fixes
would be needed in 2.5, I've left them out.
* Also in creator.c: there was code for a python bugfix where the screen was not
initialized when running with -P. The code that initializes the screen there
I had to disable, that can't work in 2.5 anymore but left it commented as a
reminder.
Further I had to disable some new function calls. using src/ and python/, as
was done already in this branch, disabled function calls:
* bpath.c: error reporting
* BME_conversions.c: editmesh conversion functions.
* SHD_dynamic: disabled almost completely, there is no python/.
* KX_PythonInit.cpp and Ketsji/ build files: Mathutils is not there, disabled.
* text.c: clipboard copy call.
* object.c: OB_SUPPORT_MATERIAL.
* DerivedMesh.c and subsurf_ccg, stipple_quarttone.
Still to be done:
* Go over files and functions that were moved to a different location but could
still use changes that were done in trunk.
Diffstat (limited to 'source/blender/blenkernel/intern/effect.c')
-rw-r--r-- | source/blender/blenkernel/intern/effect.c | 2107 |
1 files changed, 283 insertions, 1824 deletions
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 881e67eef8a..66e8a039dda 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -58,6 +58,7 @@ #include "BKE_anim.h" /* needed for where_on_path */ #include "BKE_armature.h" #include "BKE_blender.h" +#include "BKE_collision.h" #include "BKE_constraint.h" #include "BKE_deform.h" #include "BKE_depsgraph.h" @@ -98,43 +99,19 @@ typedef struct VeNoCo { float co[3], no[3]; } VeNoCo; -Effect *add_effect(int type) +/* ***************** PARTICLES ***************** */ + +/* deprecated, only keep this for readfile.c */ +PartEff *give_parteff(Object *ob) { - Effect *eff=0; PartEff *paf; - int a; - switch(type) { - case EFF_PARTICLE: - paf= MEM_callocN(sizeof(PartEff), "neweff"); - eff= (Effect *)paf; - - paf->sta= 1.0; - paf->end= 100.0; - paf->lifetime= 50.0; - for(a=0; a<PAF_MAXMULT; a++) { - paf->life[a]= 50.0; - paf->child[a]= 4; - paf->mat[a]= 1; - } - - paf->totpart= 1000; - paf->totkey= 8; - paf->staticstep= 5; - paf->defvec[2]= 1.0f; - paf->nabla= 0.05f; - paf->disp = 100; - paf->speedtex = 8; - paf->omat = 1; - paf->flag= PAF_FACE; - - break; + paf= ob->effect.first; + while(paf) { + if(paf->type==EFF_PARTICLE) return paf; + paf= paf->next; } - - eff->type= eff->buttype= type; - eff->flag |= SELECT; - - return eff; + return 0; } void free_effect(Effect *eff) @@ -161,172 +138,6 @@ void free_effects(ListBase *lb) } } -Effect *copy_effect(Effect *eff) -{ - Effect *effn; - - effn= MEM_dupallocN(eff); - if(effn->type==EFF_PARTICLE) ((PartEff *)effn)->keys= 0; - - return effn; -} - -void copy_act_effect(Object *ob) -{ - /* return a copy of the active effect */ - Effect *effn, *eff; - - eff= ob->effect.first; - while(eff) { - if(eff->flag & SELECT) { - - effn= copy_effect(eff); - BLI_addtail(&ob->effect, effn); - - eff->flag &= ~SELECT; - return; - - } - eff= eff->next; - } - - /* when it comes here: add new effect */ - eff= add_effect(EFF_PARTICLE); - BLI_addtail(&ob->effect, eff); - -} - -void copy_effects(ListBase *lbn, ListBase *lb) -{ - Effect *eff, *effn; - - lbn->first= lbn->last= 0; - - eff= lb->first; - while(eff) { - effn= copy_effect(eff); - BLI_addtail(lbn, effn); - - eff= eff->next; - } - -} - -void deselectall_eff(Object *ob) -{ - Effect *eff= ob->effect.first; - - while(eff) { - eff->flag &= ~SELECT; - eff= eff->next; - } -} - -/* ***************** PARTICLES ***************** */ - -static Particle *new_particle(PartEff *paf) -{ - static Particle *pa; - static int cur; - - /* we agree: when paf->keys==0: alloc */ - if(paf->keys==NULL) { - pa= paf->keys= MEM_callocN( paf->totkey*paf->totpart*sizeof(Particle), "particlekeys" ); - cur= 0; - } - else { - if(cur && cur<paf->totpart) pa+=paf->totkey; - cur++; - } - return pa; -} - -PartEff *give_parteff(Object *ob) -{ - PartEff *paf; - - paf= ob->effect.first; - while(paf) { - if(paf->type==EFF_PARTICLE) return paf; - paf= paf->next; - } - return 0; -} - -void where_is_particle(PartEff *paf, Particle *pa, float ctime, float *vec) -{ - Particle *p[4]; - float dt, t[4]; - int a; - - if(paf->totkey==1 || ctime < pa->time) { - VECCOPY(vec, pa->co); - return; - } - - /* first find the first particlekey */ - a= (int)((paf->totkey-1)*(ctime-pa->time)/pa->lifetime); - if(a>=paf->totkey) a= paf->totkey-1; - else if(a<0) a= 0; - - pa+= a; - - if(a>0) p[0]= pa-1; else p[0]= pa; - p[1]= pa; - - if(a+1<paf->totkey) p[2]= pa+1; else p[2]= pa; - if(a+2<paf->totkey) p[3]= pa+2; else p[3]= p[2]; - - if(p[1]==p[2] || p[2]->time == p[1]->time) dt= 0.0; - else dt= (ctime-p[1]->time)/(p[2]->time - p[1]->time); - - if(paf->flag & PAF_BSPLINE) set_four_ipo(dt, t, KEY_BSPLINE); - else set_four_ipo(dt, t, KEY_CARDINAL); - - vec[0]= t[0]*p[0]->co[0] + t[1]*p[1]->co[0] + t[2]*p[2]->co[0] + t[3]*p[3]->co[0]; - vec[1]= t[0]*p[0]->co[1] + t[1]*p[1]->co[1] + t[2]*p[2]->co[1] + t[3]*p[3]->co[1]; - vec[2]= t[0]*p[0]->co[2] + t[1]*p[1]->co[2] + t[2]*p[2]->co[2] + t[3]*p[3]->co[2]; - -} - -static void particle_tex(MTex *mtex, PartEff *paf, float *co, float *no) -{ - float tin, tr, tg, tb, ta; - float old; - - externtex(mtex, co, &tin, &tr, &tg, &tb, &ta); - - if(paf->texmap==PAF_TEXINT) { - tin*= paf->texfac; - no[0]+= tin*paf->defvec[0]; - no[1]+= tin*paf->defvec[1]; - no[2]+= tin*paf->defvec[2]; - } - else if(paf->texmap==PAF_TEXRGB) { - no[0]+= (tr-0.5f)*paf->texfac; - no[1]+= (tg-0.5f)*paf->texfac; - no[2]+= (tb-0.5f)*paf->texfac; - } - else { /* PAF_TEXGRAD */ - - old= tin; - co[0]+= paf->nabla; - externtex(mtex, co, &tin, &tr, &tg, &tb, &ta); - no[0]+= (old-tin)*paf->texfac; - - co[0]-= paf->nabla; - co[1]+= paf->nabla; - externtex(mtex, co, &tin, &tr, &tg, &tb, &ta); - no[1]+= (old-tin)*paf->texfac; - - co[1]-= paf->nabla; - co[2]+= paf->nabla; - externtex(mtex, co, &tin, &tr, &tg, &tb, &ta); - no[2]+= (old-tin)*paf->texfac; - - } -} - /* -------------------------- Effectors ------------------ */ static void add_to_effectorcache(ListBase *lb, Object *ob, Object *obsrc) @@ -349,6 +160,13 @@ static void add_to_effectorcache(ListBase *lb, Object *ob, Object *obsrc) } } else if(pd->forcefield) { + + if(pd->forcefield == PFIELD_WIND) + { + pd->rng = rng_new(1); + rng_srandom(pd->rng, (unsigned int)(ceil(PIL_check_seconds_timer()))); // use better seed + } + ec= MEM_callocN(sizeof(pEffectorCache), "effector cache"); ec->ob= ob; BLI_addtail(lb, ec); @@ -397,1713 +215,354 @@ void pdEndEffectors(ListBase *lb) pEffectorCache *ec; /* restore full copy */ for(ec= lb->first; ec; ec= ec->next) + { + if(ec->ob->pd && (ec->ob->pd->forcefield == PFIELD_WIND)) + rng_free(ec->ob->pd->rng); + *(ec->ob)= ec->obcopy; + } BLI_freelistN(lb); } } -/* local for this c file, only for guides now */ -static void precalc_effectors(Object *ob, PartEff *paf, Particle *pa, ListBase *lb) -{ - pEffectorCache *ec; - - for(ec= lb->first; ec; ec= ec->next) { - PartDeflect *pd= ec->ob->pd; - - ec->oldspeed[0]= ec->oldspeed[1]= ec->oldspeed[2]= 0.0f; - - if(pd->forcefield==PFIELD_GUIDE && ec->ob->type==OB_CURVE) { - float vec[4], dir[3]; - - if(!(paf->flag & PAF_STATIC)) - where_is_object_time(ec->ob, pa->time); - - /* scale corrects speed vector to curve size */ - if(paf->totkey>1) ec->scale= (paf->totkey-1)/pa->lifetime; - else ec->scale= 1.0f; - - /* time_scale is for random life */ - if(pa->lifetime>paf->lifetime) - ec->time_scale= paf->lifetime/pa->lifetime; - else - ec->time_scale= pa->lifetime/paf->lifetime; - - /* distance of first path point to particle origin */ - where_on_path(ec->ob, 0.0f, vec, dir); - VECCOPY(ec->oldloc, vec); /* store local coord for differences */ - Mat4MulVecfl(ec->ob->obmat, vec); - - /* for static we need to move to global space */ - if(paf->flag & PAF_STATIC) { - VECCOPY(dir, pa->co); - Mat4MulVecfl(ob->obmat, dir); - ec->guide_dist= VecLenf(vec, dir); - } - else - ec->guide_dist= VecLenf(vec, pa->co); - } - } -} +/************************************************/ +/* Effectors */ +/************************************************/ -/* -------- pdDoEffectors() -------- - generic force/speed system, now used for particles and softbodies - lb = listbase with objects that take part in effecting - opco = global coord, as input - force = force accumulator - speed = actual current speed which can be altered - cur_time = "external" time in frames, is constant for static particles - loc_time = "local" time in frames, range <0-1> for the lifetime of particle - par_layer = layer the caller is in - flags = only used for softbody wind now - guide = old speed of particle +// triangle - ray callback function +static void eff_tri_ray_hit(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + // whenever we hit a bounding box, we don't check further + hit->dist = -1; + hit->index = 1; +} -*/ -void pdDoEffectors(ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags) +// get visibility of a wind ray +static float eff_calc_visibility(Object *ob, float *co, float *dir) { -/* - Modifies the force on a particle according to its - relation with the effector object - Different kind of effectors include: - Forcefields: Gravity-like attractor - (force power is related to the inverse of distance to the power of a falloff value) - Vortex fields: swirling effectors - (particles rotate around Z-axis of the object. otherwise, same relation as) - (Forcefields, but this is not done through a force/acceleration) - Guide: particles on a path - (particles are guided along a curve bezier or old nurbs) - (is independent of other effectors) -*/ - Object *ob; - pEffectorCache *ec; - PartDeflect *pd; - float vect_to_vert[3]; - float f_force, force_vec[3]; - float *obloc; - float distance, force_val, ffall_val; - float guidecollect[3], guidedist= 0.0f; - int cur_frame; + CollisionModifierData **collobjs = NULL; + int numcollobj = 0, i; + float norm[3], len = 0.0; + float visibility = 1.0; - guidecollect[0]= guidecollect[1]= guidecollect[2]=0.0f; - - /* Cycle through collected objects, get total of (1/(gravity_strength * dist^gravity_power)) */ - /* Check for min distance here? (yes would be cool to add that, ton) */ + collobjs = get_collisionobjects(ob, &numcollobj); - for(ec = lb->first; ec; ec= ec->next) { - /* object effectors were fully checked to be OK to evaluate! */ - ob= ec->ob; - pd= ob->pd; - - /* Get IPO force strength and fall off values here */ - if (has_ipo_code(ob->ipo, OB_PD_FSTR)) - force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, cur_time); - else - force_val = pd->f_strength; + if(!collobjs) + return 0; + + VECCOPY(norm, dir); + VecMulf(norm, -1.0); + len = Normalize(norm); + + // check all collision objects + for(i = 0; i < numcollobj; i++) + { + CollisionModifierData *collmd = collobjs[i]; - if (has_ipo_code(ob->ipo, OB_PD_FFALL)) - ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, cur_time); - else - ffall_val = pd->f_power; + if(collmd->bvhtree) + { + BVHTreeRayHit hit; - /* Need to set r.cfra for paths (investigate, ton) (uses ob->ctime now, ton) */ - if(ob->ctime!=cur_time) { - cur_frame = G.scene->r.cfra; - G.scene->r.cfra = (int)cur_time; - where_is_object_time(ob, cur_time); - G.scene->r.cfra = cur_frame; - } - - /* use center of object for distance calculus */ - obloc= ob->obmat[3]; - VECSUB(vect_to_vert, obloc, opco); - distance = VecLength(vect_to_vert); + hit.index = -1; + hit.dist = len + FLT_EPSILON; - if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist && pd->forcefield != PFIELD_GUIDE) - ; /* don't do anything */ - else if(pd->forcefield == PFIELD_WIND) { - VECCOPY(force_vec, ob->obmat[2]); - - /* wind works harder perpendicular to normal, would be nice for softbody later (ton) */ - - /* Limit minimum distance to vertex so that */ - /* the force is not too big */ - if (distance < 0.001) distance = 0.001f; - f_force = (force_val)*(1/(1000 * (float)pow((double)distance, (double)ffall_val))); - /* this option for softbody only */ - if(flags && PE_WIND_AS_SPEED){ - speed[0] -= (force_vec[0] * f_force ); - speed[1] -= (force_vec[1] * f_force ); - speed[2] -= (force_vec[2] * f_force ); - } - else{ - force[0] += force_vec[0]*f_force; - force[1] += force_vec[1]*f_force; - force[2] += force_vec[2]*f_force; - } - } - else if(pd->forcefield == PFIELD_FORCE) { - - /* only use center of object */ - obloc= ob->obmat[3]; - - /* Now calculate the gravitational force */ - VECSUB(vect_to_vert, obloc, opco); - distance = VecLength(vect_to_vert); - - /* Limit minimum distance to vertex so that */ - /* the force is not too big */ - if (distance < 0.001) distance = 0.001f; - f_force = (force_val)*(1.0/(1000.0 * (float)pow((double)distance, (double)ffall_val))); - force[0] += (vect_to_vert[0] * f_force ); - force[1] += (vect_to_vert[1] * f_force ); - force[2] += (vect_to_vert[2] * f_force ); - } - else if(pd->forcefield == PFIELD_VORTEX) { - float vortexvec[3]; - - /* only use center of object */ - obloc= ob->obmat[3]; - - /* Now calculate the vortex force */ - VECSUB(vect_to_vert, obloc, opco); - distance = VecLength(vect_to_vert); - - Crossf(force_vec, ob->obmat[2], vect_to_vert); - Normalize(force_vec); - - /* Limit minimum distance to vertex so that */ - /* the force is not too big */ - if (distance < 0.001) distance = 0.001f; - f_force = (force_val)*(1.0/(100.0 * (float)pow((double)distance, (double)ffall_val))); - vortexvec[0]= -(force_vec[0] * f_force ); - vortexvec[1]= -(force_vec[1] * f_force ); - vortexvec[2]= -(force_vec[2] * f_force ); - - /* this option for softbody only */ - if(flags &&PE_WIND_AS_SPEED) { - speed[0]+= vortexvec[0]; - speed[1]+= vortexvec[1]; - speed[2]+= vortexvec[2]; - } - else { - /* since vortex alters the speed, we have to correct for the previous vortex result */ - speed[0]+= vortexvec[0] - ec->oldspeed[0]; - speed[1]+= vortexvec[1] - ec->oldspeed[1]; - speed[2]+= vortexvec[2] - ec->oldspeed[2]; + // check if the way is blocked + if(BLI_bvhtree_ray_cast(collmd->bvhtree, co, norm, 0.0f, &hit, eff_tri_ray_hit, NULL)>=0) + { + // visibility is only between 0 and 1, calculated from 1-absorption + visibility *= MAX2(0.0, MIN2(1.0, (1.0-((float)collmd->absorption)*0.01))); - VECCOPY(ec->oldspeed, vortexvec); + if(visibility <= 0.0f) + break; } } - else if(pd->forcefield == PFIELD_GUIDE) { - float guidevec[4], guidedir[3]; - float mindist= force_val; /* force_val is actually mindist in the UI */ - - distance= ec->guide_dist; - - /* WARNING: bails out with continue here */ - if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist) continue; - - /* calculate contribution factor for this guide */ - if(distance<=mindist) f_force= 1.0f; - else if(pd->flag & PFIELD_USEMAX) { - if(distance>pd->maxdist || mindist>=pd->maxdist) f_force= 0.0f; - else { - f_force= 1.0f - (distance-mindist)/(pd->maxdist - mindist); - if(ffall_val!=0.0f) - f_force = (float)pow(f_force, ffall_val+1.0); - } - } - else { - f_force= 1.0f/(1.0f + distance-mindist); - if(ffall_val!=0.0f) - f_force = (float)pow(f_force, ffall_val+1.0); - } - - /* now derive path point from loc_time */ - if(pd->flag & PFIELD_GUIDE_PATH_ADD) - where_on_path(ob, f_force*loc_time*ec->time_scale, guidevec, guidedir); - else - where_on_path(ob, loc_time*ec->time_scale, guidevec, guidedir); - - VECSUB(guidedir, guidevec, ec->oldloc); - VECCOPY(ec->oldloc, guidevec); - - Mat4Mul3Vecfl(ob->obmat, guidedir); - VecMulf(guidedir, ec->scale); /* correction for lifetime and speed */ - - /* we subtract the speed we gave it previous step */ - VECCOPY(guidevec, guidedir); - VECSUB(guidedir, guidedir, ec->oldspeed); - VECCOPY(ec->oldspeed, guidevec); - - /* if it fully contributes, we stop */ - if(f_force==1.0) { - VECCOPY(guidecollect, guidedir); - guidedist= 1.0f; - break; - } - else if(guidedist<1.0f) { - VecMulf(guidedir, f_force); - VECADD(guidecollect, guidecollect, guidedir); - guidedist += f_force; - } - } - } - - /* all guides are accumulated here */ - if(guidedist!=0.0f) { - if(guidedist!=1.0f) VecMulf(guidecollect, 1.0f/guidedist); - VECADD(speed, speed, guidecollect); } -} - -static void cache_object_vertices(Object *ob) -{ - Mesh *me; - MVert *mvert; - float *fp; - int a; - me= ob->data; - if(me->totvert==0) return; - - fp= ob->sumohandle= MEM_mallocN(3*sizeof(float)*me->totvert, "cache particles"); - mvert= me->mvert; - a= me->totvert; - while(a--) { - VECCOPY(fp, mvert->co); - Mat4MulVecfl(ob->obmat, fp); - mvert++; - fp+= 3; - } + MEM_freeN(collobjs); + + return visibility; } -static int pdDoDeflection(RNG *rng, float opco[3], float npco[3], float opno[3], - float npno[3], float life, float force[3], int def_depth, - float cur_time, unsigned int par_layer, int *last_object, - int *last_face, int *same_face) +// noise function for wind e.g. +static float wind_func(struct RNG *rng, float strength) { - /* Particle deflection code */ - /* The code is in two sections: the first part checks whether a particle has */ - /* intersected a face of a deflector mesh, given its old and new co-ords, opco and npco */ - /* and which face it hit first */ - /* The second part calculates the new co-ordinates given that collision and updates */ - /* the new co-ordinates accordingly */ - Base *base; - Object *ob, *deflection_object = NULL; - Mesh *def_mesh; - MFace *mface, *deflection_face = NULL; - float *v1, *v2, *v3, *v4, *vcache=NULL; - float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3]; - float dv1[3] = {0}, dv2[3] = {0}, dv3[3] = {0}; - float vect_to_int[3], refl_vel[3]; - float d_intersect_co[3], d_intersect_vect[3], d_nvect[3], d_i_co_above[3]; - float forcec[3]; - float k_point3, dist_to_plane; - float first_dist, ref_plane_mag; - float dk_plane=0, dk_point1=0; - float icalctop, icalcbot, n_mag; - float mag_iv, x_m,y_m,z_m; - float damping, perm_thresh; - float perm_val, rdamp_val; - int a, deflected=0, deflected_now=0; - float t,t2, min_t; - float mat[3][3], obloc[3] = {0}; - int cur_frame; - float time_before, time_after; - float force_mag_norm; - int d_object=0, d_face=0, ds_object=0, ds_face=0; - - first_dist = 200000; - min_t = 200000; - - /* The first part of the code, finding the first intersected face*/ - base= G.scene->base.first; - while (base) { - /*Only proceed for mesh object in same layer */ - if(base->object->type==OB_MESH && (base->lay & par_layer)) { - ob= base->object; - /* only with deflecting set */ - if(ob->pd && ob->pd->deflect) { - def_mesh= ob->data; - - d_object = d_object + 1; - - d_face = d_face + 1; - mface= def_mesh->mface; - a = def_mesh->totface; - - - if(ob->parent==NULL && ob->ipo==NULL) { // static - if(ob->sumohandle==NULL) cache_object_vertices(ob); - vcache= ob->sumohandle; - } - else { - /*Find out where the object is at this time*/ - cur_frame = G.scene->r.cfra; - G.scene->r.cfra = (int)cur_time; - where_is_object_time(ob, cur_time); - G.scene->r.cfra = cur_frame; - - /*Pass the values from ob->obmat to mat*/ - /*and the location values to obloc */ - Mat3CpyMat4(mat,ob->obmat); - obloc[0] = ob->obmat[3][0]; - obloc[1] = ob->obmat[3][1]; - obloc[2] = ob->obmat[3][2]; - vcache= NULL; - - } - - while (a--) { - - if(vcache) { - v1= vcache+ 3*(mface->v1); - VECCOPY(nv1, v1); - v1= vcache+ 3*(mface->v2); - VECCOPY(nv2, v1); - v1= vcache+ 3*(mface->v3); - VECCOPY(nv3, v1); - v1= vcache+ 3*(mface->v4); - VECCOPY(nv4, v1); - } - else { - /* Calculate the global co-ordinates of the vertices*/ - v1= (def_mesh->mvert+(mface->v1))->co; - v2= (def_mesh->mvert+(mface->v2))->co; - v3= (def_mesh->mvert+(mface->v3))->co; - v4= (def_mesh->mvert+(mface->v4))->co; + int random = (rng_getInt(rng)+1) % 65535; // max 2357 + float force = rng_getFloat(rng) + 1.0f; + float ret; + float sign = 0; - VECCOPY(nv1, v1); - VECCOPY(nv2, v2); - VECCOPY(nv3, v3); - VECCOPY(nv4, v4); + sign = (random > 32000.0) ? 1.0: -1.0; // dividing by 2 is not giving equal sign distribution - /*Apply the objects deformation matrix*/ - Mat3MulVecfl(mat, nv1); - Mat3MulVecfl(mat, nv2); - Mat3MulVecfl(mat, nv3); - Mat3MulVecfl(mat, nv4); + ret = sign*((float)random / force)*strength/65535.0f; - VECADD(nv1, nv1, obloc); - VECADD(nv2, nv2, obloc); - VECADD(nv3, nv3, obloc); - VECADD(nv4, nv4, obloc); - } - - deflected_now = 0; - - - -// t= 0.5; // this is labda of line, can use it optimize quad intersection -// sorry but no .. see below (BM) - if( LineIntersectsTriangle(opco, npco, nv1, nv2, nv3, &t, NULL) ) { - if (t < min_t) { - deflected = 1; - deflected_now = 1; - } - } -// else if (mface->v4 && (t>=0.0 && t<=1.0)) { -// no, you can't skip testing the other triangle -// it might give a smaller t on (close to) the edge .. this is numerics not esoteric maths :) -// note: the 2 triangles don't need to share a plane ! (BM) - if (mface->v4) { - if( LineIntersectsTriangle(opco, npco, nv1, nv3, nv4, &t2, NULL) ) { - if (t2 < min_t) { - deflected = 1; - deflected_now = 2; - } - } - } - - if ((deflected_now > 0) && ((t < min_t) ||(t2 < min_t))) { - min_t = t; - ds_object = d_object; - ds_face = d_face; - deflection_object = ob; - deflection_face = mface; - if (deflected_now==1) { - min_t = t; - VECCOPY(dv1, nv1); - VECCOPY(dv2, nv2); - VECCOPY(dv3, nv3); - } - else { - min_t = t2; - VECCOPY(dv1, nv1); - VECCOPY(dv2, nv3); - VECCOPY(dv3, nv4); - } - } - mface++; - } - } - } - base = base->next; - } - - - /* Here's the point to do the permeability calculation */ - /* Set deflected to 0 if a random number is below the value */ - /* Get the permeability IPO here*/ - if (deflected) { - - if (has_ipo_code(deflection_object->ipo, OB_PD_PERM)) - perm_val = IPO_GetFloatValue(deflection_object->ipo, OB_PD_PERM, cur_time); - else - perm_val = deflection_object->pd->pdef_perm; - - perm_thresh = rng_getFloat(rng) - perm_val; - if (perm_thresh < 0 ) { - deflected = 0; - } - } - - /* Now for the second part of the deflection code - work out the new speed */ - /* and position of the particle if a collision occurred */ - if (deflected) { - VECSUB(edge1, dv1, dv2); - VECSUB(edge2, dv3, dv2); - Crossf(d_nvect, edge2, edge1); - n_mag = Normalize(d_nvect); - dk_plane = INPR(d_nvect, nv1); - dk_point1 = INPR(d_nvect,opco); - - VECSUB(d_intersect_vect, npco, opco); - - d_intersect_co[0] = opco[0] + (min_t * (npco[0] - opco[0])); - d_intersect_co[1] = opco[1] + (min_t * (npco[1] - opco[1])); - d_intersect_co[2] = opco[2] + (min_t * (npco[2] - opco[2])); - - d_i_co_above[0] = (d_intersect_co[0] + (0.001f * d_nvect[0])); - d_i_co_above[1] = (d_intersect_co[1] + (0.001f * d_nvect[1])); - d_i_co_above[2] = (d_intersect_co[2] + (0.001f * d_nvect[2])); - mag_iv = Normalize(d_intersect_vect); - VECCOPY(npco, d_intersect_co); - - VECSUB(vect_to_int, opco, d_intersect_co); - first_dist = Normalize(vect_to_int); - - /* Work out the lengths of time before and after collision*/ - time_before = (life*(first_dist / (mag_iv))); - time_after = (life*((mag_iv - first_dist) / (mag_iv))); - - /* We have to recalculate what the speed would have been at the */ - /* point of collision, not the key frame time */ - npno[0]= opno[0] + time_before*force[0]; - npno[1]= opno[1] + time_before*force[1]; - npno[2]= opno[2] + time_before*force[2]; - - - /* Reflect the speed vector in the face */ - x_m = (2 * npno[0] * d_nvect[0]); - y_m = (2 * npno[1] * d_nvect[1]); - z_m = (2 * npno[2] * d_nvect[2]); - refl_vel[0] = npno[0] - (d_nvect[0] * (x_m + y_m + z_m)); - refl_vel[1] = npno[1] - (d_nvect[1] * (x_m + y_m + z_m)); - refl_vel[2] = npno[2] - (d_nvect[2] * (x_m + y_m + z_m)); - - /*A random variation in the damping factor........ */ - /*Get the IPO values for damping here*/ - - if (has_ipo_code(deflection_object->ipo, OB_PD_SDAMP)) - damping = IPO_GetFloatValue(deflection_object->ipo, OB_PD_SDAMP, cur_time); - else - damping = deflection_object->pd->pdef_damp; - - if (has_ipo_code(deflection_object->ipo, OB_PD_RDAMP)) - rdamp_val = IPO_GetFloatValue(deflection_object->ipo, OB_PD_RDAMP, cur_time); - else - rdamp_val = deflection_object->pd->pdef_rdamp; - - damping = damping + ((1.0f - damping) * rng_getFloat(rng) *rdamp_val); - damping = damping * damping; - ref_plane_mag = INPR(refl_vel,d_nvect); - - if (damping > 0.999) damping = 0.999f; - - /* Now add in the damping force - only damp in the direction of */ - /* the faces normal vector */ - npno[0] = (refl_vel[0] - (d_nvect[0] * ref_plane_mag * damping)); - npno[1] = (refl_vel[1] - (d_nvect[1] * ref_plane_mag * damping)); - npno[2] = (refl_vel[2] - (d_nvect[2] * ref_plane_mag * damping)); - - /* Now reset opno */ - VECCOPY(opno,npno); - VECCOPY(forcec, force); - - /* If the particle has bounced more than four times on the same */ - /* face within this cycle (depth > 4, same face > 4 ) */ - /* Then set the force to be only that component of the force */ - /* in the same direction as the face normal */ - /* i.e. subtract the component of the force in the direction */ - /* of the face normal from the actual force */ - if ((ds_object == *last_object) && (ds_face == *last_face)) { - /* Increment same_face */ - *same_face = *same_face + 1; - if ((*same_face > 3) && (def_depth > 3)) { - force_mag_norm = INPR(forcec, d_nvect); - forcec[0] = forcec[0] - (d_nvect[0] * force_mag_norm); - forcec[1] = forcec[1] - (d_nvect[1] * force_mag_norm); - forcec[2] = forcec[2] - (d_nvect[2] * force_mag_norm); - } - } - else *same_face = 1; - - *last_object = ds_object; - *last_face = ds_face; - - /* We have the particles speed at the point of collision */ - /* Now we want the particles speed at the current key frame */ - - npno[0]= npno[0] + time_after*forcec[0]; - npno[1]= npno[1] + time_after*forcec[1]; - npno[2]= npno[2] + time_after*forcec[2]; - - /* Now we have to recalculate pa->co for the remainder*/ - /* of the time since the intersect*/ - npco[0]= npco[0] + time_after*npno[0]; - npco[1]= npco[1] + time_after*npno[1]; - npco[2]= npco[2] + time_after*npno[2]; - - /* And set the old co-ordinates back to the point just above the intersection */ - VECCOPY(opco, d_i_co_above); - - /* Finally update the time */ - life = time_after; - cur_time += time_before; - - /* The particle may have fallen through the face again by now!!*/ - /* So check if the particle has changed sides of the plane compared*/ - /* the co-ordinates at the last keyframe*/ - /* But only do this as a last resort, if we've got to the end of the */ - /* number of collisions allowed */ - if (def_depth==9) { - k_point3 = INPR(d_nvect,npco); - if (((dk_plane > k_point3) && (dk_plane < dk_point1))||((dk_plane < k_point3) && (dk_plane > dk_point1))) { - - /* Yup, the pesky particle may have fallen through a hole!!! */ - /* So we'll cheat a bit and move the particle along the normal vector */ - /* until it's just the other side of the plane */ - icalctop = (dk_plane - d_nvect[0]*npco[0] - d_nvect[1]*npco[1] - d_nvect[2]*npco[2]); - icalcbot = (d_nvect[0]*d_nvect[0] + d_nvect[1]*d_nvect[1] + d_nvect[2]*d_nvect[2]); - dist_to_plane = icalctop / icalcbot; - - /* Now just increase the distance a little to place */ - /* the point the other side of the plane */ - dist_to_plane *= 1.1f; - npco[0]= npco[0] + (dist_to_plane * d_nvect[0]); - npco[1]= npco[1] + (dist_to_plane * d_nvect[1]); - npco[2]= npco[2] + (dist_to_plane * d_nvect[2]); - - } - } - } - return deflected; + return ret; } -/* - rng= random number generator - ob = object that spawns the particles - depth = for fireworks - nr = index nr of current particle - paf = the particle system - part = current particle - force = force vector - deform = flag to indicate lattice deform - */ -static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff *paf, Particle *part, float *force, int deform, MTex *mtex, ListBase *effectorbase) + +static float falloff_func(float fac, int usemin, float mindist, int usemax, float maxdist, float power) { - Particle *pa, *opa = NULL; - float damp, deltalife, life; - float cur_time, maxspeed= paf->maxlen/(float)paf->totkey; - float opco[3], opno[3], npco[3], npno[3], new_force[3], new_speed[3]; - int b, rt1, rt2, deflected, deflection, finish_defs, def_count; - int last_ob, last_fc, same_fc; - - damp= 1.0f-paf->damp; - pa= part; - - /* start speed: random */ - if(paf->randfac!=0.0) { - pa->no[0]+= paf->randfac*(rng_getFloat(rng) - 0.5f); - pa->no[1]+= paf->randfac*(rng_getFloat(rng) - 0.5f); - pa->no[2]+= paf->randfac*(rng_getFloat(rng) - 0.5f); - } + if(!usemin) + mindist= 0.0f; - /* start speed: texture */ - if(mtex && paf->texfac!=0.0) { - particle_tex(mtex, paf, pa->co, pa->no); + if(fac < mindist) { + return 1.0f; } + else if(usemax) { + if(fac>maxdist || (maxdist-mindist)<=0.0f) + return 0.0f; - /* effectors here? */ - if(effectorbase) - precalc_effectors(ob, paf, pa, effectorbase); - - if(paf->totkey>1) deltalife= pa->lifetime/(paf->totkey-1); - else deltalife= pa->lifetime; - - /* longer lifetime results in longer distance covered */ - VecMulf(pa->no, deltalife); - - opa= pa; - pa++; - - for(b=1; b<paf->totkey; b++) { - - /* new time */ - pa->time= opa->time+deltalife; - cur_time = pa->time; - - /* set initial variables */ - VECCOPY(opco, opa->co); - VECCOPY(new_force, force); - VECCOPY(new_speed, opa->no); - VecMulf(new_speed, 1.0f/deltalife); - //new_speed[0] = new_speed[1] = new_speed[2] = 0.0f; - - /* handle differences between static (local coords, fixed frame) and dynamic */ - if(effectorbase) { - float loc_time= ((float)b)/(float)(paf->totkey-1); - - if(paf->flag & PAF_STATIC) { - float opco1[3], new_force1[3]; - - /* move co and force to global coords */ - VECCOPY(opco1, opco); - Mat4MulVecfl(ob->obmat, opco1); - VECCOPY(new_force1, new_force); - Mat4Mul3Vecfl(ob->obmat, new_force1); - Mat4Mul3Vecfl(ob->obmat, new_speed); - - cur_time = G.scene->r.cfra; - - /* force fields */ - pdDoEffectors(effectorbase, opco1, new_force1, new_speed, cur_time, loc_time, 0); - - /* move co, force and newspeed back to local */ - VECCOPY(opco, opco1); - Mat4MulVecfl(ob->imat, opco); - VECCOPY(new_force, new_force1); - Mat4Mul3Vecfl(ob->imat, new_force); - Mat4Mul3Vecfl(ob->imat, new_speed); - } - else { - /* force fields */ - pdDoEffectors(effectorbase, opco, new_force, new_speed, cur_time, loc_time, 0); - } - } - - /* new speed */ - pa->no[0]= deltalife * (new_speed[0] + new_force[0]); - pa->no[1]= deltalife * (new_speed[1] + new_force[1]); - pa->no[2]= deltalife * (new_speed[2] + new_force[2]); - - /* speed limitor */ - if((paf->flag & PAF_STATIC) && maxspeed!=0.0f) { - float len= VecLength(pa->no); - if(len > maxspeed) - VecMulf(pa->no, maxspeed/len); - } - - /* new location */ - pa->co[0]= opa->co[0] + pa->no[0]; - pa->co[1]= opa->co[1] + pa->no[1]; - pa->co[2]= opa->co[2] + pa->no[2]; - - /* Particle deflection code */ - if((paf->flag & PAF_STATIC)==0) { - deflection = 0; - finish_defs = 1; - def_count = 0; - - VECCOPY(opno, opa->no); - VECCOPY(npco, pa->co); - VECCOPY(npno, pa->no); - - life = deltalife; - cur_time -= deltalife; - - last_ob = -1; - last_fc = -1; - same_fc = 0; - - /* First call the particle deflection check for the particle moving */ - /* between the old co-ordinates and the new co-ordinates */ - /* If a deflection occurs, call the code again, this time between the */ - /* intersection point and the updated new co-ordinates */ - /* Bail out if we've done the calculation 10 times - this seems ok */ - /* for most scenes I've tested */ - while (finish_defs) { - deflected = pdDoDeflection(rng, opco, npco, opno, npno, life, new_force, - def_count, cur_time, ob->lay, - &last_ob, &last_fc, &same_fc); - if (deflected) { - def_count = def_count + 1; - deflection = 1; - if (def_count==10) finish_defs = 0; - } - else { - finish_defs = 0; - } - } - - /* Only update the particle positions and speed if we had a deflection */ - if (deflection) { - pa->co[0] = npco[0]; - pa->co[1] = npco[1]; - pa->co[2] = npco[2]; - pa->no[0] = npno[0]; - pa->no[1] = npno[1]; - pa->no[2] = npno[2]; - } - } - - /* speed: texture */ - if(mtex && paf->texfac!=0.0) { - particle_tex(mtex, paf, pa->co, pa->no); - } - if(damp!=1.0) { - pa->no[0]*= damp; - pa->no[1]*= damp; - pa->no[2]*= damp; - } - - opa= pa; - pa++; - /* opa is used later on too! */ + fac= (fac-mindist)/(maxdist-mindist); + return 1.0f - (float)pow((double)fac, (double)power); } + else + return pow((double)1.0f+fac-mindist, (double)-power); +} - if(deform) { - /* deform all keys */ - pa= part; - b= paf->totkey; - while(b--) { - calc_latt_deform(pa->co, 1.0f); - pa++; - } - } - - /* the big multiplication */ - if(depth<PAF_MAXMULT && paf->mult[depth]!=0.0) { - - /* new 'child' emerges from an average 'mult' part from - the particles */ - damp = (float)nr; - rt1= (int)(damp*paf->mult[depth]); - rt2= (int)((damp+1.0)*paf->mult[depth]); - if(rt1!=rt2) { - - for(b=0; b<paf->child[depth]; b++) { - pa= new_particle(paf); - *pa= *opa; - pa->lifetime= paf->life[depth]; - if(paf->randlife!=0.0) { - pa->lifetime*= 1.0f + paf->randlife*(rng_getFloat(rng) - 0.5f); - } - pa->mat_nr= paf->mat[depth]; +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); +} - make_particle_keys(rng, ob, depth+1, b, paf, pa, force, deform, mtex, effectorbase); - } - } - } +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 void init_mv_jit(float *jit, int num, int seed2) +float effector_falloff(PartDeflect *pd, float *eff_velocity, float *vec_to_part) { - RNG *rng; - float *jit2, x, rad1, rad2, rad3; - int i, num2; + float eff_dir[3], temp[3]; + float falloff=1.0, fac, r_fac; + + if(pd->forcefield==PFIELD_LENNARDJ) + return falloff; /* Lennard-Jones field has it's own falloff built in */ + + 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; - if(num==0) return; + 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; - rad1= (float)(1.0/sqrt((float)num)); - rad2= (float)(1.0/((float)num)); - rad3= (float)sqrt((float)num)/((float)num); + r_fac=saacos(fac/VecLength(vec_to_part))*180.0f/(float)M_PI; + falloff*= falloff_func_rad(pd, r_fac); - rng = rng_new(31415926 + num + seed2); - x= 0; - num2 = 2 * num; - for(i=0; i<num2; i+=2) { - - jit[i]= x + rad1*(0.5f - rng_getFloat(rng)); - jit[i+1]= i/(2.0f*num) + rad1*(0.5f - rng_getFloat(rng)); - - jit[i]-= (float)floor(jit[i]); - jit[i+1]-= (float)floor(jit[i+1]); - - x+= rad3; - x -= (float)floor(x); + break; } - jit2= MEM_mallocN(12 + 2*sizeof(float)*num, "initjit"); - - for (i=0 ; i<4 ; i++) { - BLI_jitterate1(jit, jit2, num, rad1); - BLI_jitterate1(jit, jit2, num, rad1); - BLI_jitterate2(jit, jit2, num, rad2); - } - MEM_freeN(jit2); - rng_free(rng); + return falloff; } -#define JIT_RAND 32 - -/* for a position within a face, tot is total amount of faces */ -static void give_mesh_particle_coord(PartEff *paf, VeNoCo *noco, MFace *mface, int partnr, int subnr, float *co, float *no) +void do_physical_effector(Object *ob, float *opco, 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, struct RNG *rng, float noise_factor, float charge, float pa_size) { - static float *jit= NULL; - static float *trands= NULL; - static int jitlevel= 1; - float *v1, *v2, *v3, *v4; - float u, v; - float *n1, *n2, *n3, *n4; - - /* free signal */ - if(paf==NULL) { - if(jit) MEM_freeN(jit); - jit= NULL; - if(trands) MEM_freeN(trands); - trands= NULL; + float mag_vec[3]={0,0,0}; + float temp[3], temp2[3]; + float eff_vel[3]; + float noise = 0, visibility; + + // calculate visibility + visibility = eff_calc_visibility(ob, opco, vec_to_part); + if(visibility <= 0.0) return; - } - - /* first time initialize jitter or trand, partnr then is total amount of particles, subnr total amount of faces */ - if(trands==NULL && jit==NULL) { - RNG *rng = rng_new(31415926 + paf->seed); - int i, tot; - - if(paf->flag & PAF_TRAND) - tot= partnr; - else - tot= JIT_RAND; /* arbitrary... allows JIT_RAND times more particles in a face for jittered distro */ - - trands= MEM_callocN(2+2*tot*sizeof(float), "trands"); - for(i=0; i<tot; i++) { - trands[2*i]= rng_getFloat(rng); - trands[2*i+1]= rng_getFloat(rng); - } - rng_free(rng); + falloff *= visibility; - if((paf->flag & PAF_TRAND)==0) { - jitlevel= paf->userjit; + VecCopyf(eff_vel,eff_velocity); + Normalize(eff_vel); + + switch(type){ + case PFIELD_WIND: + VECCOPY(mag_vec,eff_vel); - if(jitlevel == 0) { - jitlevel= partnr/subnr; - if(paf->flag & PAF_EDISTR) jitlevel*= 2; /* looks better in general, not very scietific */ - if(jitlevel<3) jitlevel= 3; - if(jitlevel>100) jitlevel= 100; - } + // add wind noise here, only if we have wind + if((noise_factor > 0.0f) && (force_val > FLT_EPSILON)) + noise = wind_func(rng, noise_factor); - jit= MEM_callocN(2+ jitlevel*2*sizeof(float), "jit"); - init_mv_jit(jit, jitlevel, paf->seed); - BLI_array_randomize(jit, 2*sizeof(float), jitlevel, paf->seed); /* for custom jit or even distribution */ - } - return; - } - - if(paf->flag & PAF_TRAND) { - u= trands[2*partnr]; - v= trands[2*partnr+1]; - } - else { - /* jittered distribution gets fixed random offset */ - if(subnr>=jitlevel) { - int jitrand= (subnr/jitlevel) % JIT_RAND; - - subnr %= jitlevel; - u= jit[2*subnr] + trands[2*jitrand]; - v= jit[2*subnr+1] + trands[2*jitrand+1]; - if(u > 1.0f) u-= 1.0f; - if(v > 1.0f) v-= 1.0f; - } - else { - u= jit[2*subnr]; - v= jit[2*subnr+1]; - } - } - - v1= (noco+(mface->v1))->co; - v2= (noco+(mface->v2))->co; - v3= (noco+(mface->v3))->co; - n1= (noco+(mface->v1))->no; - n2= (noco+(mface->v2))->no; - n3= (noco+(mface->v3))->no; - - if(mface->v4) { - float uv= u*v; - float muv= (1.0f-u)*(v); - float umv= (u)*(1.0f-v); - float mumv= (1.0f-u)*(1.0f-v); - - v4= (noco+(mface->v4))->co; - n4= (noco+(mface->v4))->no; - - co[0]= mumv*v1[0] + muv*v2[0] + uv*v3[0] + umv*v4[0]; - co[1]= mumv*v1[1] + muv*v2[1] + uv*v3[1] + umv*v4[1]; - co[2]= mumv*v1[2] + muv*v2[2] + uv*v3[2] + umv*v4[2]; + VecMulf(mag_vec,(force_val+noise)*falloff); + VecAddf(field,field,mag_vec); + break; - no[0]= mumv*n1[0] + muv*n2[0] + uv*n3[0] + umv*n4[0]; - no[1]= mumv*n1[1] + muv*n2[1] + uv*n3[1] + umv*n4[1]; - no[2]= mumv*n1[2] + muv*n2[2] + uv*n3[2] + umv*n4[2]; - } - else { - /* mirror triangle uv coordinates when on other side */ - if(u + v > 1.0f) { - u= 1.0f-u; - v= 1.0f-v; - } - co[0]= v1[0] + u*(v3[0]-v1[0]) + v*(v2[0]-v1[0]); - co[1]= v1[1] + u*(v3[1]-v1[1]) + v*(v2[1]-v1[1]); - co[2]= v1[2] + u*(v3[2]-v1[2]) + v*(v2[2]-v1[2]); - - no[0]= n1[0] + u*(n3[0]-n1[0]) + v*(n2[0]-n1[0]); - no[1]= n1[1] + u*(n3[1]-n1[1]) + v*(n2[1]-n1[1]); - no[2]= n1[2] + u*(n3[2]-n1[2]) + v*(n2[2]-n1[2]); - } -} + case PFIELD_FORCE: + if(planar) + Projf(mag_vec,vec_to_part,eff_vel); + else + VecCopyf(mag_vec,vec_to_part); + Normalize(mag_vec); -/* Gets a MDeformVert's weight in group (0 if not in group) */ -/* note; this call could be in mesh.c or deform.c, but OK... it's in armature.c too! (ton) */ -static float vert_weight(MDeformVert *dvert, int group) -{ - MDeformWeight *dw; - int i; - - if(dvert) { - dw= dvert->dw; - for(i= dvert->totweight; i>0; i--, dw++) { - if(dw->def_nr == group) return dw->weight; - if(i==1) break; /*otherwise dw will point to somewhere it shouldn't*/ - } - } - return 0.0; -} + VecMulf(mag_vec,force_val*falloff); + VecAddf(field,field,mag_vec); + break; -/* Gets a faces average weight in a group, helper for below, face and weights are always set */ -static float face_weight(MFace *face, float *weights) -{ - float tweight; - - tweight = weights[face->v1] + weights[face->v2] + weights[face->v3]; - - if(face->v4) { - tweight += weights[face->v4]; - tweight /= 4.0; - } - else { - tweight /= 3.0; - } + case PFIELD_VORTEX: + Crossf(mag_vec,eff_vel,vec_to_part); - return tweight; -} + Normalize(mag_vec); -/* helper function for build_particle_system() */ -static void make_weight_tables(PartEff *paf, Mesh *me, int totpart, VeNoCo *vertlist, int totvert, MFace *facelist, int totface, float **vweights, float **fweights) -{ - MFace *mface; - float *foweights=NULL, *voweights=NULL; - float totvweight=0.0f, totfweight=0.0f; - int a; - - if((paf->flag & PAF_FACE)==0) totface= 0; - - /* collect emitting vertices & faces if vert groups used */ - if(paf->vertgroup && me->dvert) { - - /* allocate weights array for all vertices, also for lookup of faces later on. note it's a malloc */ - *vweights= voweights= MEM_mallocN( totvert*sizeof(float), "pafvoweights" ); - totvweight= 0.0f; - for(a=0; a<totvert; a++) { - voweights[a]= vert_weight(me->dvert+a, paf->vertgroup-1); - totvweight+= voweights[a]; - } - - if(totface) { - /* allocate weights array for faces, note it's a malloc */ - *fweights= foweights= MEM_mallocN(totface*sizeof(float), "paffoweights" ); - for(a=0, mface=facelist; a<totface; a++, mface++) { - foweights[a] = face_weight(mface, voweights); - } - } - } - - /* make weights for faces or for even area distribution */ - if(totface && (paf->flag & PAF_EDISTR)) { - float maxfarea= 0.0f, curfarea; - - /* two cases for area distro, second case we already have group weights */ - if(foweights==NULL) { - /* allocate weights array for faces, note it's a malloc */ - *fweights= foweights= MEM_mallocN(totface*sizeof(float), "paffoweights" ); - - for(a=0, mface=facelist; a<totface; a++, mface++) { - if (mface->v4) - curfarea= AreaQ3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co, vertlist[mface->v4].co); - else - curfarea= AreaT3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co); - if(curfarea>maxfarea) - maxfarea = curfarea; - foweights[a]= curfarea; - } - } - else { - for(a=0, mface=facelist; a<totface; a++, mface++) { - if(foweights[a]!=0.0f) { - if (mface->v4) - curfarea= AreaQ3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co, vertlist[mface->v4].co); - else - curfarea= AreaT3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co); - if(curfarea>maxfarea) - maxfarea = curfarea; - foweights[a]*= curfarea; - } - } - } - - /* normalize weights for max face area, calculate tot */ - if(maxfarea!=0.0f) { - maxfarea= 1.0f/maxfarea; - for(a=0; a< totface; a++) { - if(foweights[a]!=0.0) { - foweights[a] *= maxfarea; - totfweight+= foweights[a]; - } - } - } - } - else if(foweights) { - /* only add totfweight value */ - for(a=0; a< totface; a++) { - if(foweights[a]!=0.0) { - totfweight+= foweights[a]; - } - } - } - - /* if weight arrays, we turn these arrays into the amount of particles */ - if(totvert && voweights) { - float mult= (float)totpart/totvweight; - - for(a=0; a< totvert; a++) { - if(voweights[a]!=0.0) - voweights[a] *= mult; - } - } - - if(totface && foweights) { - float mult= (float)totpart/totfweight; - - for(a=0; a< totface; a++) { - if(foweights[a]!=0.0) - foweights[a] *= mult; - } - } -} + VecMulf(mag_vec,force_val*distance*falloff); + VecAddf(field,field,mag_vec); -/* helper function for build_particle_system() */ -static void make_length_tables(PartEff *paf, Mesh *me, int totvert, MFace *facelist, int totface, float **vlengths, float **flengths) -{ - MFace *mface; - float *folengths=NULL, *volengths=NULL; - int a; - - if((paf->flag & PAF_FACE)==0) totface= 0; - - /* collect emitting vertices & faces if vert groups used */ - if(paf->vertgroup_v && me->dvert) { - - /* allocate lengths array for all vertices, also for lookup of faces later on. note it's a malloc */ - *vlengths= volengths= MEM_mallocN( totvert*sizeof(float), "pafvolengths" ); - for(a=0; a<totvert; a++) { - volengths[a]= vert_weight(me->dvert+a, paf->vertgroup_v-1); - } - - if(totface) { - /* allocate lengths array for faces, note it's a malloc */ - *flengths= folengths= MEM_mallocN(totface*sizeof(float), "paffolengths" ); - for(a=0, mface=facelist; a<totface; a++, mface++) { - folengths[a] = face_weight(mface, volengths); - } - } - } -} + break; + case PFIELD_MAGNET: + if(planar) + VecCopyf(temp,eff_vel); + else + /* magnetic field of a moving charge */ + Crossf(temp,eff_vel,vec_to_part); + Normalize(temp); -/* for paf start to end, store all matrices for objects */ -typedef struct pMatrixCache { - float obmat[4][4]; - float imat[3][3]; -} pMatrixCache; + 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); -/* WARN: this function stores data in ob->id.idnew! */ -/* error: this function changes ob->recalc of other objects... */ -static pMatrixCache *cache_object_matrices(Object *ob, int start, int end) -{ - pMatrixCache *mcache, *mc; - Group *group= NULL; - Object *obcopy; - Base *base; - float framelenold, cfrao, sfo; - - /* object can be linked in group... stupid exception */ - if(NULL==object_in_scene(ob, G.scene)) - group= find_group(ob); - - mcache= mc= MEM_mallocN( (end-start+1)*sizeof(pMatrixCache), "ob matrix cache"); - - framelenold= G.scene->r.framelen; - G.scene->r.framelen= 1.0f; - cfrao= G.scene->r.cfra; - sfo= ob->sf; - ob->sf= 0.0f; - - /* clear storage, copy recalc tag (bad loop) */ - for(obcopy= G.main->object.first; obcopy; obcopy= obcopy->id.next) { - obcopy->id.newid= NULL; - obcopy->recalco= obcopy->recalc; - obcopy->recalc= 0; - } - - /* all objects get tagged recalc that influence this object (does group too) */ - /* note that recalco has the real recalc tags, set by callers of this function */ - ob->recalc |= OB_RECALC_OB; /* make sure a recalc gets flushed */ - DAG_object_update_flags(G.scene, ob, -1); - - for(G.scene->r.cfra= start; G.scene->r.cfra<=end; G.scene->r.cfra++, mc++) { - - if(group) { - GroupObject *go; - - for(go= group->gobject.first; go; go= go->next) { - if(go->ob->recalc) { - where_is_object(go->ob); - - do_ob_key(go->ob); - if(go->ob->type==OB_ARMATURE) { - do_all_pose_actions(go->ob); // only does this object actions - where_is_pose(go->ob); - } - } - } - } - else { - for(base= G.scene->base.first; base; base= base->next) { - if(base->object->recalc) { - if(base->object->id.newid==NULL) - base->object->id.newid= MEM_dupallocN(base->object); - - where_is_object(base->object); - - do_ob_key(base->object); - if(base->object->type==OB_ARMATURE) { - do_all_pose_actions(base->object); // only does this object actions - where_is_pose(base->object); - } - } - } - } - Mat4CpyMat4(mc->obmat, ob->obmat); - Mat4Invert(ob->imat, ob->obmat); - Mat3CpyMat4(mc->imat, ob->imat); - Mat3Transp(mc->imat); - } - - /* restore */ - G.scene->r.cfra= cfrao; - G.scene->r.framelen= framelenold; - ob->sf= sfo; - - if(group) { - GroupObject *go; - - for(go= group->gobject.first; go; go= go->next) { - if(go->ob->recalc) { - where_is_object(go->ob); - - do_ob_key(go->ob); - if(go->ob->type==OB_ARMATURE) { - do_all_pose_actions(go->ob); // only does this object actions - where_is_pose(go->ob); - } - } - } - } - else { - for(base= G.scene->base.first; base; base= base->next) { - if(base->object->recalc) { - - if(base->object->id.newid) { - obcopy= (Object *)base->object->id.newid; - *(base->object) = *(obcopy); - MEM_freeN(obcopy); - base->object->id.newid= NULL; - } - - do_ob_key(base->object); - if(base->object->type==OB_ARMATURE) { - do_all_pose_actions(base->object); // only does this object actions - where_is_pose(base->object); - } - } - } - } - - /* copy recalc tag (bad loop) */ - for(obcopy= G.main->object.first; obcopy; obcopy= obcopy->id.next) - obcopy->recalc= obcopy->recalco; - - return mcache; -} + Normalize(mag_vec); -/* for fluidsim win32 debug messages */ -#if defined(WIN32) && (!(defined snprintf)) -#define snprintf _snprintf -#endif + VecMulf(mag_vec,force_val*falloff); + VecSubf(field,field,mag_vec); -/* main particle building function - one day particles should become dynamic (realtime) with the current method as a 'bake' (ton) */ -void build_particle_system(Object *ob) -{ - RNG *rng; - PartEff *paf; - Particle *pa; - Mesh *me; - Base *base; - MTex *mtexmove=0, *mtextime=0; - Material *ma; - MFace *facelist= NULL; - pMatrixCache *mcache=NULL, *mcnow, *mcprev; - ListBase *effectorbase; - VeNoCo *vertexcosnos; - double startseconds= PIL_check_seconds_timer(); - float ftime, dtime, force[3], vec[3], fac, co[3], no[3]; - float *voweights= NULL, *foweights= NULL, maxw=1.0f; - float *volengths= NULL, *folengths= NULL; - int deform=0, a, totpart, paf_sta, paf_end; - int waitcursor_set= 0, totvert, totface, curface, curvert; -#ifndef DISABLE_ELBEEM - int readMask, activeParts, fileParts; -#endif - - /* return conditions */ - if(ob->type!=OB_MESH) return; - me= ob->data; + 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_CHARGE: + if(planar) + Projf(mag_vec,vec_to_part,eff_vel); + else + VecCopyf(mag_vec,vec_to_part); - paf= give_parteff(ob); - if(paf==NULL) return; - - if(G.rendering==0 && paf->disp==0) return; - - if(paf->keys) MEM_freeN(paf->keys); /* free as early as possible, for returns */ - paf->keys= NULL; - - //printf("build particles\n"); - - /* fluid sim particle import handling, actual loading of particles from file */ - #ifndef DISABLE_ELBEEM - if( (1) && (ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && // broken, disabled for now! - (ob->fluidsimSettings) && - (ob->fluidsimSettings->type == OB_FLUIDSIM_PARTICLE)) { - char *suffix = "fluidsurface_particles_#"; - char *suffix2 = ".gz"; - char filename[256]; - char debugStrBuffer[256]; - int curFrame = G.scene->r.cfra -1; // warning - sync with derived mesh fsmesh loading - int j, numFileParts; - gzFile gzf; - float vel[3]; - - if(ob==G.obedit) { // off... - paf->totpart = 0; // 1 or 0? - return; - } + Normalize(mag_vec); - // ok, start loading - strcpy(filename, ob->fluidsimSettings->surfdataPath); - strcat(filename, suffix); - BLI_convertstringcode(filename, G.sce, curFrame); // fixed #frame-no - strcat(filename, suffix2); - - gzf = gzopen(filename, "rb"); - if (!gzf) { - snprintf(debugStrBuffer,256,"readFsPartData::error - Unable to open file for reading '%s' \n", filename); - //elbeemDebugOut(debugStrBuffer); - paf->totpart = 0; - return; - } + VecMulf(mag_vec,charge*force_val*falloff); + VecAddf(field,field,mag_vec); + break; + case PFIELD_LENNARDJ: + { + float fac; - gzread(gzf, &totpart, sizeof(totpart)); - numFileParts = totpart; - totpart = (G.rendering)?totpart:(paf->disp*totpart)/100; - paf->totpart= totpart; - paf->totkey= 1; - /* initialize particles */ - new_particle(paf); - ftime = 0.0; // unused... - - // set up reading mask - readMask = ob->fluidsimSettings->typeFlags; - activeParts=0; - fileParts=0; - - for(a=0; a<totpart; a++) { - int ptype=0; - short shsize=0; - float convertSize=0.0; - gzread(gzf, &ptype, sizeof( ptype )); - if(ptype&readMask) { - activeParts++; - pa= new_particle(paf); - pa->time= ftime; - pa->lifetime= ftime + 10000.; // add large number to make sure they are displayed, G.scene->r.efra +1.0; - pa->co[0] = 0.0; - pa->co[1] = - pa->co[2] = 1.0*(float)a / (float)totpart; - pa->no[0] = pa->no[1] = pa->no[2] = 0.0; - pa->mat_nr= paf->omat; - gzread(gzf, &convertSize, sizeof( float )); - // convert range of 1.0-10.0 to shorts 1000-10000) - shsize = (short)(convertSize*1000.0); - pa->rt = shsize; - - for(j=0; j<3; j++) { - float wrf; - gzread(gzf, &wrf, sizeof( wrf )); - pa->co[j] = wrf; - //fprintf(stderr,"Rj%d ",j); - } - for(j=0; j<3; j++) { - float wrf; - gzread(gzf, &wrf, sizeof( wrf )); - vel[j] = wrf; - } - //if(a<25) fprintf(stderr,"FSPARTICLE debug set %s , a%d = %f,%f,%f , life=%f \n", filename, a, pa->co[0],pa->co[1],pa->co[2], pa->lifetime ); - } else { - // skip... - for(j=0; j<2*3+1; j++) { - float wrf; gzread(gzf, &wrf, sizeof( wrf )); - } + if(planar) { + Projf(mag_vec,vec_to_part,eff_vel); + distance = VecLength(mag_vec); } - fileParts++; - } - gzclose( gzf ); - - totpart = paf->totpart = activeParts; - snprintf(debugStrBuffer,256,"readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d \n", paf->totpart,activeParts,fileParts,readMask); - elbeemDebugOut(debugStrBuffer); - return; - } // fluid sim particles done - #endif // DISABLE_ELBEEM - - if(paf->end < paf->sta) return; - - if( (paf->flag & PAF_OFACE) && (paf->flag & PAF_FACE)==0) return; - - if(me->totvert==0) return; - - if(ob==G.obedit) return; - totpart= (G.rendering)?paf->totpart:(paf->disp*paf->totpart)/100; - if(totpart==0) return; - - /* No returns after this line! */ - - /* material */ - ma= give_current_material(ob, paf->omat); - if(ma) { - if(paf->speedtex) - mtexmove= ma->mtex[paf->speedtex-1]; - mtextime= ma->mtex[paf->timetex-1]; - } + else + VecCopyf(mag_vec,vec_to_part); - disable_speed_curve(1); /* check this... */ + /* at this distance the field is 60 times weaker than maximum */ + if(distance > 2.22 * (size+pa_size)) + break; - /* initialize particles */ - new_particle(paf); + fac = pow((size+pa_size)/distance,6.0); + + fac = - fac * (1.0 - fac) / distance; - /* reset deflector cache, sumohandle is free, but its still sorta abuse... (ton) */ - for(base= G.scene->base.first; base; base= base->next) - base->object->sumohandle= NULL; + /* limit the repulsive term drastically to avoid huge forces */ + fac = ((fac>2.0) ? 2.0 : fac); - /* all object positions from start to end */ - paf_sta= (int)floor(paf->sta); - paf_end= (int)ceil(paf->end); - if((paf->flag & PAF_STATIC)==0) - mcache= cache_object_matrices(ob, paf_sta, paf_end); - - /* mult generations? */ - for(a=0; a<PAF_MAXMULT; a++) { - if(paf->mult[a]!=0.0) { - /* interesting formula! this way after 'x' generations the total is paf->totpart */ - totpart= (int)(totpart / (1.0+paf->mult[a]*paf->child[a])); + /* 0.003715 is the fac value at 2.22 times (size+pa_size), + substracted to avoid discontinuity at the border + */ + VecMulf(mag_vec, force_val * (fac-0.0037315)); + VecAddf(field,field,mag_vec); + break; } - else break; } +} - /* for static particles, calculate system on current frame (? ton) */ - if(ma) do_mat_ipo(ma); - - /* matrix invert for static too */ - Mat4Invert(ob->imat, ob->obmat); - Mat4CpyMat4(paf->imat, ob->imat); /* used for duplicators */ - - /* new random generator */ - rng = rng_new(paf->seed); - - /* otherwise it goes way too fast */ - force[0]= paf->force[0]*0.05f; - force[1]= paf->force[1]*0.05f; - force[2]= paf->force[2]*0.05f; - - if( paf->flag & PAF_STATIC ) deform= 0; - else { - Object *parlatt= modifiers_isDeformedByLattice(ob); - if(parlatt) { - deform= 1; - init_latt_deform(parlatt, 0); - } - } - - /* get the effectors */ - effectorbase= pdInitEffectors(ob, paf->group); - - /* init geometry, return is 6 x float * me->totvert in size */ - vertexcosnos= (VeNoCo *)mesh_get_mapped_verts_nors(ob); - facelist= me->mface; - totvert= me->totvert; - totface= me->totface; - - /* if vertexweights or even distribution, it makes weight tables, also checks where it emits from */ - make_weight_tables(paf, me, totpart, vertexcosnos, totvert, facelist, totface, &voweights, &foweights); - - /* vertexweights can define lengths too */ - make_length_tables(paf, me, totvert, facelist, totface, &volengths, &folengths); - - /* now define where to emit from, if there are face weights we skip vertices */ - if(paf->flag & PAF_OFACE) totvert= 0; - if((paf->flag & PAF_FACE)==0) totface= 0; - if(foweights) totvert= 0; - - /* initialize give_mesh_particle_coord */ - if(totface) - give_mesh_particle_coord(paf, vertexcosnos, facelist, totpart, totface, NULL, NULL); - - /* correction for face timing when using weighted average */ - if(totface && foweights) { - maxw= (paf->end-paf->sta)/foweights[0]; - } - else if(totvert && voweights) { - maxw= (paf->end-paf->sta)/voweights[0]; - } - - /* for loop below */ - if (paf->flag & PAF_STATIC) { - ftime = G.scene->r.cfra; - dtime= 0.0f; - } else { - ftime= paf->sta; - dtime= (paf->end - paf->sta)/(float)totpart; - } - - curface= curvert= 0; - for(a=0; a<totpart; a++, ftime+=dtime) { - - /* we set waitcursor only when a half second expired, particles now are realtime updated */ - if(waitcursor_set==0 && (a % 256)==255) { - double seconds= PIL_check_seconds_timer(); - if(seconds - startseconds > 0.5) { - //XXX waitcursor(1); - waitcursor_set= 1; - } - } - - pa= new_particle(paf); - pa->time= ftime; +/* -------- pdDoEffectors() -------- + generic force/speed system, now used for particles and softbodies + lb = listbase with objects that take part in effecting + opco = global coord, as input + force = force accumulator + speed = actual current speed which can be altered + cur_time = "external" time in frames, is constant for static particles + loc_time = "local" time in frames, range <0-1> for the lifetime of particle + par_layer = layer the caller is in + flags = only used for softbody wind now + guide = old speed of particle - /* get coordinates from faces, only when vertices set to zero */ - if(totvert==0 && totface) { - int curjit; - - /* use weight table, we have to do faces in order to be able to use jitter table... */ - if(foweights) { - - if(foweights[curface] < 1.0f) { - float remainder= 0.0f; - - while(remainder + foweights[curface] < 1.0f && curface<totface-1) { - remainder += foweights[curface]; - curface++; - } - /* if this is the last face, the foweights[] can be zero, so we don't add a particle extra */ - if(curface!=totface-1) - foweights[curface] += remainder; - - maxw= (paf->end-paf->sta)/foweights[curface]; - } +*/ +void pdDoEffectors(ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags) +{ +/* + Modifies the force on a particle according to its + relation with the effector object + Different kind of effectors include: + Forcefields: Gravity-like attractor + (force power is related to the inverse of distance to the power of a falloff value) + Vortex fields: swirling effectors + (particles rotate around Z-axis of the object. otherwise, same relation as) + (Forcefields, but this is not done through a force/acceleration) + Guide: particles on a path + (particles are guided along a curve bezier or old nurbs) + (is independent of other effectors) +*/ + Object *ob; + pEffectorCache *ec; + PartDeflect *pd; + + float distance, vec_to_part[3]; + float falloff; - if(foweights[curface]==0.0f) - break; /* WARN skips here out of particle generating */ - else { - if(foweights[curface] >= 1.0f) /* note the >= here, this because of the < 1.0f above, it otherwise will stick to 1 face forever */ - foweights[curface] -= 1.0f; - - curjit= (int) foweights[curface]; - give_mesh_particle_coord(paf, vertexcosnos, facelist+curface, a, curjit, co, no); - - /* time correction to make particles appear evenly, maxw does interframe (0-1) */ - pa->time= paf->sta + maxw*foweights[curface]; - } - } - else { - curface= a % totface; - curjit= a/totface; - give_mesh_particle_coord(paf, vertexcosnos, facelist+curface, a, curjit, co, no); - } - } - /* get coordinates from vertices */ - if(totvert) { - /* use weight table */ - if(voweights) { - - if(voweights[curvert] < 1.0f) { - float remainder= 0.0f; - - while(remainder + voweights[curvert] < 1.0f && curvert<totvert-1) { - remainder += voweights[curvert]; - curvert++; - } - voweights[curvert] += remainder; - maxw= (paf->end-paf->sta)/voweights[curvert]; - } - - if(voweights[curvert]==0.0f) - break; /* WARN skips here out of particle generating */ - else { - if(voweights[curvert] > 1.0f) - voweights[curvert] -= 1.0f; - - /* time correction to make particles appear evenly */ - pa->time= paf->sta + maxw*voweights[curvert]; - } - } - else { - curvert= a % totvert; - if(a >= totvert && totface) - totvert= 0; - } + /* Cycle through collected objects, get total of (1/(gravity_strength * dist^gravity_power)) */ + /* Check for min distance here? (yes would be cool to add that, ton) */ + + for(ec = lb->first; ec; ec= ec->next) { + /* object effectors were fully checked to be OK to evaluate! */ + ob= ec->ob; + pd= ob->pd; - VECCOPY(co, vertexcosnos[curvert].co); - VECCOPY(no, vertexcosnos[curvert].no); - } - - VECCOPY(pa->co, co); - - /* dynamic options */ - if((paf->flag & PAF_STATIC)==0) { - int cur; + /* Get IPO force strength and fall off values here */ + where_is_object_time(ob,cur_time); - /* particle retiming with texture */ - if(mtextime && (paf->flag2 & PAF_TEXTIME)) { - float tin, tr, tg, tb, ta, orco[3]; - - /* calculate normalized orco */ - orco[0] = (co[0]-me->loc[0])/me->size[0]; - orco[1] = (co[1]-me->loc[1])/me->size[1]; - orco[2] = (co[2]-me->loc[2])/me->size[2]; - externtex(mtextime, orco, &tin, &tr, &tg, &tb, &ta); - - if(paf->flag2neg & PAF_TEXTIME) - pa->time = paf->sta + (paf->end - paf->sta)*tin; - else - pa->time = paf->sta + (paf->end - paf->sta)*(1.0f-tin); - } + /* use center of object for distance calculus */ + VecSubf(vec_to_part, opco, ob->obmat[3]); + distance = VecLength(vec_to_part); - /* set ob at correct time, we use cached matrices */ - cur= (int)floor(pa->time) + 1 ; /* + 1 has a reason: (obmat/prevobmat) otherwise comet-tails start too late */ - - if(cur <= paf_end) mcnow= mcache + cur - paf_sta; - else mcnow= mcache + paf_end - paf_sta; - - if(cur > paf_sta) mcprev= mcnow-1; - else mcprev= mcache; - - /* move to global space */ - Mat4MulVecfl(mcnow->obmat, pa->co); + falloff=effector_falloff(pd,ob->obmat[2],vec_to_part); - VECCOPY(vec, co); - Mat4MulVecfl(mcprev->obmat, vec); - - /* first start speed: object */ - VECSUB(pa->no, pa->co, vec); - - VecMulf(pa->no, paf->obfac); - - /* calculate the correct inter-frame */ - fac= (pa->time- (float)floor(pa->time)); - pa->co[0]= fac*pa->co[0] + (1.0f-fac)*vec[0]; - pa->co[1]= fac*pa->co[1] + (1.0f-fac)*vec[1]; - pa->co[2]= fac*pa->co[2] + (1.0f-fac)*vec[2]; - - /* start speed: normal */ - if(paf->normfac!=0.0) { - /* imat is transpose ! */ - VECCOPY(vec, no); - Mat3MulVecfl(mcnow->imat, vec); - - Normalize(vec); - VecMulf(vec, paf->normfac); - VECADD(pa->no, pa->no, vec); - } - } + if(falloff<=0.0f) + ; /* don't do anything */ else { - if(paf->normfac!=0.0) { - VECCOPY(pa->no, no); - Normalize(pa->no); - VecMulf(pa->no, paf->normfac); - } - } - - pa->lifetime= paf->lifetime; - if(paf->randlife!=0.0) { - pa->lifetime*= 1.0f + paf->randlife*(rng_getFloat(rng) - 0.5f); - } - pa->mat_nr= paf->omat; - - if(folengths) - pa->lifetime*= folengths[curface]; - - make_particle_keys(rng, ob, 0, a, paf, pa, force, deform, mtexmove, effectorbase); - } - - /* free stuff */ - give_mesh_particle_coord(NULL, NULL, NULL, 0, 0, NULL, NULL); - MEM_freeN(vertexcosnos); - if(voweights) MEM_freeN(voweights); - if(foweights) MEM_freeN(foweights); - if(volengths) MEM_freeN(volengths); - if(folengths) MEM_freeN(folengths); - if(mcache) MEM_freeN(mcache); - rng_free(rng); - - if(deform) end_latt_deform(); - - if(effectorbase) - pdEndEffectors(effectorbase); - - /* reset deflector cache */ - for(base= G.scene->base.first; base; base= base->next) { - if(base->object->sumohandle) { + float field[3]={0,0,0}, tmp[3]; + VECCOPY(field, force); + do_physical_effector(ob, opco, pd->forcefield,pd->f_strength,distance, + falloff,pd->f_dist,pd->f_damp,ob->obmat[2],vec_to_part, + speed,force,pd->flag&PFIELD_PLANAR, pd->rng, pd->f_noise, 0.0f, 0.0f); - MEM_freeN(base->object->sumohandle); - base->object->sumohandle= NULL; + // for softbody backward compatibility + if(flags & PE_WIND_AS_SPEED){ + VECSUB(tmp, force, field); + VECSUB(speed, speed, tmp); + } } } - - disable_speed_curve(0); - - //XXX if(waitcursor_set) waitcursor(0); } - |