Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/effect.c')
-rw-r--r--source/blender/blenkernel/intern/effect.c2107
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);
}
-