diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index cb58496465f..9ebafdff3e4 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -57,7 +57,9 @@ void build_particle_system(struct Object *ob); /* particle deflector */ #define PE_WIND_AS_SPEED 0x00000001 -void pdDoEffector(float *opco, float *force, float *speed, float cur_time, unsigned int par_layer,unsigned int flags); +struct ListBase *pdInitEffectors(unsigned int layer); +void pdEndEffectors(struct ListBase *lb); +void pdDoEffectors(struct ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags); diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 4d08f958057..dcd49f9f0b2 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -200,6 +200,7 @@ int interval_test(int min, int max, int p1, int cycl) } /* warning, *vec needs FOUR items! */ +/* ctime is normalized range <0-1> */ int where_on_path(Object *ob, float ctime, float *vec, float *dir) /* returns OK */ { Curve *cu; @@ -488,29 +489,29 @@ void particle_duplilist(Scene *sce, Object *par, PartEff *paf) } else { // non static particles - if(ctime > pa->time) { - if(ctime < pa->time+pa->lifetime) { - newob= new_dupli_object(&duplilist, ob, par); + if((paf->flag & PAF_UNBORN)==0 && ctime < pa->time) continue; + if((paf->flag & PAF_DIED)==0 && ctime > pa->time+pa->lifetime) continue; - /* to give ipos in object correct offset */ - where_is_object_time(newob, ctime-pa->time); - - where_is_particle(paf, pa, ctime, vec); - if(paf->stype==PAF_VECT) { - where_is_particle(paf, pa, ctime+1.0f, vec1); - - VecSubf(vec1, vec1, vec); - q2= vectoquat(vec1, ob->trackflag, ob->upflag); + //if(ctime < pa->time+pa->lifetime) { + newob= new_dupli_object(&duplilist, ob, par); + + /* to give ipos in object correct offset */ + where_is_object_time(newob, ctime-pa->time); - QuatToMat3(q2, mat); - Mat4CpyMat4(tmat, newob->obmat); - Mat4MulMat43(newob->obmat, tmat, mat); - } - - VECCOPY(newob->obmat[3], vec); - } + where_is_particle(paf, pa, ctime, vec); + if(paf->stype==PAF_VECT) { + where_is_particle(paf, pa, ctime+1.0f, vec1); + + VecSubf(vec1, vec1, vec); + q2= vectoquat(vec1, ob->trackflag, ob->upflag); + + QuatToMat3(q2, mat); + Mat4CpyMat4(tmat, newob->obmat); + Mat4MulMat43(newob->obmat, tmat, mat); } - } + + VECCOPY(newob->obmat[3], vec); + } } break; } diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 8bb010a7847..d211305f0f3 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -467,9 +467,13 @@ struct DagForest *build_dag(struct Scene *sce, short mask) } else if(ob->type==OB_MESH) { PartEff *paf= give_parteff(ob); - if(paf && (paf->flag & PAF_STATIC)) { + if(paf) { Base *base1; + /* ob location depends on itself */ + if((paf->flag & PAF_STATIC)==0) + dag_add_relation(dag, node, node, DAG_RL_OB_DATA); + /* force fields, warning for loop inside loop... */ for(base1 = G.scene->base.first; base1; base1= base1->next) { if( (base1->lay & base->lay) && base1->object->pd) { diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index eb4eb243000..21eafc39fc0 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -55,6 +55,7 @@ #include "BLI_rand.h" #include "BKE_action.h" +#include "BKE_anim.h" /* needed for where_on_path */ #include "BKE_armature.h" #include "BKE_bad_level_calls.h" #include "BKE_blender.h" @@ -74,8 +75,8 @@ #include "BKE_screen.h" #include "BKE_utildefines.h" -#include "render.h" // externtex, bad level call (ton) - +#include "render.h" // externtex, bad level call (ton) +#include "PIL_time.h" Effect *add_effect(int type) { @@ -102,7 +103,9 @@ Effect *add_effect(int type) paf->staticstep= 5; paf->defvec[2]= 1.0f; paf->nabla= 0.05f; - + paf->disp = 100; + paf->speedtex = 8; + paf->omat = 1; break; } @@ -205,7 +208,7 @@ static Particle *new_particle(PartEff *paf) static int cur; /* we agree: when paf->keys==0: alloc */ - if(paf->keys==0) { + if(paf->keys==NULL) { pa= paf->keys= MEM_callocN( paf->totkey*paf->totpart*sizeof(Particle), "particlekeys" ); cur= 0; } @@ -234,7 +237,7 @@ void where_is_particle(PartEff *paf, Particle *pa, float ctime, float *vec) float dt, t[4]; int a; - if(paf->totkey==1) { + if(paf->totkey==1 || ctime < pa->time) { VECCOPY(vec, pa->co); return; } @@ -252,7 +255,7 @@ void where_is_particle(PartEff *paf, Particle *pa, float ctime, float *vec) if(a+1totkey) p[2]= pa+1; else p[2]= pa; if(a+2totkey) p[3]= pa+2; else p[3]= p[2]; - if(p[1]==p[2]) dt= 0.0; + 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); @@ -301,16 +304,111 @@ static void particle_tex(MTex *mtex, PartEff *paf, float *co, float *no) } } -/* -------- pdDoEffector() -------- + +/* -------------------------- Effectors ------------------ */ + +typedef struct pEffectorCache { + struct pEffectorCache *next, *prev; + struct Object *ob; + + /* precalculated variables */ + float oldloc[3], oldspeed[3]; + float scale, time_scale; + float guide_dist; +} pEffectorCache; + + +/* returns ListBase handle with objects taking part in the effecting */ +ListBase *pdInitEffectors(unsigned int layer) +{ + static ListBase listb={NULL, NULL}; + Base *base; + + for(base = G.scene->base.first; base; base= base->next) { + if( (base->lay & layer) && base->object->pd) { + Object *ob= base->object; + PartDeflect *pd= ob->pd; + + if(pd->forcefield == PFIELD_GUIDE) { + if(ob->type==OB_CURVE) { + Curve *cu= ob->data; + if((cu->flag & CU_PATH) && cu->path && cu->path->data) { + pEffectorCache *ec= MEM_callocN(sizeof(pEffectorCache), "effector cache"); + ec->ob= ob; + BLI_addtail(&listb, ec); + } + } + } + else if(pd->forcefield) { + pEffectorCache *ec= MEM_callocN(sizeof(pEffectorCache), "effector cache"); + ec->ob= ob; + BLI_addtail(&listb, ec); + } + } + } + if(listb.first) + return &listb; + + return NULL; +} + +void pdEndEffectors(ListBase *lb) +{ + if(lb) + 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) { + if(ec->ob->type==OB_CURVE) { + float vec[4], dir[3]; + + /* 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); + } + } +} + + +/* -------- 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 = speed accumulator - cur_time = in frames + 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 */ -void pdDoEffector(float *opco, float *force, float *speed, float cur_time, unsigned int par_layer,unsigned int flags) +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 @@ -321,116 +419,186 @@ void pdDoEffector(float *opco, float *force, float *speed, float cur_time, unsig 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; - Base *base; + pEffectorCache *ec; PartDeflect *pd; float vect_to_vert[3]; - float force_vec[3]; - float f_force, distance; + float f_force, force_vec[3]; float *obloc; - float force_val, ffall_val; + float distance, force_val, ffall_val; + float guidecollect[3], guidedist= 0.0f; short cur_frame; + + guidecollect[0]= guidecollect[1]= guidecollect[2]=0.0f; - /* Cycle through objects, get total of (1/(gravity_strength * dist^gravity_power)) */ + /* 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(base = G.scene->base.first; base; base= base->next) { - if( (base->lay & par_layer) && base->object->pd) { - ob= base->object; - pd= ob->pd; + for(ec = lb->first; ec; ec= ec->next) { + /* object effectors were fully checked to be OK to evaluate! */ + ob= ec->ob; + pd= ob->pd; - /* checking if to continue or not */ - if(pd->forcefield==0) continue; + /* 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 (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; - /* 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; + /* 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 = (short)cur_time; + where_is_object_time(ob, cur_time); + G.scene->r.cfra = cur_frame; + } - 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; + /* use center of object for distance calculus */ + obloc= ob->obmat[3]; + VECSUB(vect_to_vert, obloc, opco); + distance = VecLength(vect_to_vert); + 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]); - /* 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 = (short)cur_time; - where_is_object_time(ob, cur_time); - G.scene->r.cfra = cur_frame; - } + /* wind works harder perpendicular to normal, would be nice for softbody later (ton) */ - /* use center of object for distance calculus */ - obloc= ob->obmat[3]; - VECSUB(vect_to_vert, obloc, opco); - distance = VecLength(vect_to_vert); - - if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist) - ; /* 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))); - 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/(1000 * (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) { - - /* 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); - Normalise(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/(100 * (float)pow((double)distance, (double)ffall_val))); + /* 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); + Normalise(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]; + + VECCOPY(ec->oldspeed, vortexvec); + } + } + 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; + + /* derive path point from loc_time */ + 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); + + /* 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); + } + + /* 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); } } @@ -788,11 +956,11 @@ static int pdDoDeflection(RNG *rng, float opco[3], float npco[3], float opno[3], part = current particle force = force vector deform = flag to indicate lattice deform - cfraont = current frame */ -static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff *paf, Particle *part, float *force, int deform, MTex *mtex, unsigned int par_layer, int cfraont) +static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff *paf, Particle *part, float *force, int deform, MTex *mtex, unsigned int par_layer) { Particle *pa, *opa = NULL; + ListBase *effectorbase; float damp, deltalife, life; float cur_time; float opco[3], opno[3], npco[3], npno[3], new_force[3], new_speed[3]; @@ -814,120 +982,122 @@ static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff particle_tex(mtex, paf, pa->co, pa->no); } + /* effectors here? */ + effectorbase= pdInitEffectors(par_layer); + 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++; - b= paf->totkey-1; - while(b--) { + for(b=1; btotkey; b++) { + /* new time */ pa->time= opa->time+deltalife; + cur_time = pa->time; /* set initial variables */ - opco[0] = opa->co[0]; - opco[1] = opa->co[1]; - opco[2] = opa->co[2]; + 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; - new_force[0] = force[0]; - new_force[1] = force[1]; - new_force[2] = force[2]; - new_speed[0] = 0.0; - new_speed[1] = 0.0; - new_speed[2] = 0.0; - - /* handle differences between static (local coords, fixed frae) and dynamic */ - if(paf->flag & PAF_STATIC) { - float opco1[3], new_force1[3], new_speed1[3]; + /* handle differences between static (local coords, fixed frame) and dynamic */ + if(effectorbase) { + float loc_time= ((float)b)/(float)(paf->totkey-1); - /* move to global coords */ - VECCOPY(opco1, opco); - Mat4MulVecfl(ob->obmat, opco1); - - VECCOPY(new_force1, new_force); - Mat4Mul3Vecfl(ob->obmat, new_force1); - VECCOPY(new_speed1, new_speed); - Mat4Mul3Vecfl(ob->obmat, new_speed1); - - cur_time = cfraont; - - /* force fields */ - pdDoEffector(opco1, new_force1, new_speed1, cur_time, par_layer, 0); - - /* move back to local */ - VECCOPY(opco, opco1); - Mat4MulVecfl(ob->imat, opco); - - VECCOPY(new_force, new_force1); - Mat4Mul3Vecfl(ob->imat, new_force); - VECCOPY(new_speed, new_speed1); - Mat4Mul3Vecfl(ob->imat, new_speed); - } - else { - cur_time = pa->time; - - /* force fields */ - pdDoEffector(opco, new_force, new_speed, cur_time, par_layer,0); - } - - /* new location */ - pa->co[0]= opa->co[0] + deltalife * (opa->no[0] + new_speed[0] + 0.5f*new_force[0]); - pa->co[1]= opa->co[1] + deltalife * (opa->no[1] + new_speed[1] + 0.5f*new_force[1]); - pa->co[2]= opa->co[2] + deltalife * (opa->no[2] + new_speed[2] + 0.5f*new_force[2]); - - /* new speed */ - pa->no[0]= opa->no[0] + deltalife*new_force[0]; - pa->no[1]= opa->no[1] + deltalife*new_force[1]; - pa->no[2]= opa->no[2] + deltalife*new_force[2]; - - /* Particle deflection code */ - 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, par_layer, - &last_ob, &last_fc, &same_fc); - if (deflected) { - def_count = def_count + 1; - deflection = 1; - if (def_count==10) finish_defs = 0; + 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); + + 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 { - finish_defs = 0; + /* 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]); + + /* 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]; - /* 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]; + /* 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, par_layer, + &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); @@ -937,9 +1107,7 @@ static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff pa->no[1]*= damp; pa->no[2]*= damp; } - - - + opa= pa; pa++; /* opa is used later on too! */ @@ -974,13 +1142,18 @@ static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff } pa->mat_nr= paf->mat[depth]; - make_particle_keys(rng, ob, depth+1, b, paf, pa, force, deform, mtex, par_layer, cfraont); + make_particle_keys(rng, ob, depth+1, b, paf, pa, force, deform, mtex, par_layer); } } } + + /* cleanup */ + if(effectorbase) + pdEndEffectors(effectorbase); + } -static void init_mv_jit(float *jit, int num,int seed2) +static void init_mv_jit(float *jit, int num, int seed2) { RNG *rng; float *jit2, x, rad1, rad2, rad3; @@ -1018,211 +1191,414 @@ static void init_mv_jit(float *jit, int num,int seed2) rng_free(rng); } +#define JIT_RAND 32 -static void give_mesh_mvert(Mesh *me, DispListMesh *dlm, int nr, float *co, short *no, int seed2) +/* for a position within a face, tot is total amount of faces */ +static void give_mesh_particle_coord(PartEff *paf, MVert *mvert, MFace *mface, int partnr, int subnr, float *co, short *no) { - static float *jit=0; - static int jitlevel=1; - MVert *mvert, *mvertbase=NULL; - MFace *mface, *mfacebase=NULL; - float u, v, *v1, *v2, *v3, *v4; - int totface=0, totvert=0, curface, curjit; + static float *jit= NULL; + static float *trands= NULL; + static int jitlevel= 1; + float *v1, *v2, *v3, *v4; + float u, v; short *n1, *n2, *n3, *n4; - /* signal */ - if(me==0) { + /* free signal */ + if(paf==NULL) { if(jit) MEM_freeN(jit); - jit= 0; + jit= NULL; + if(trands) MEM_freeN(trands); + trands= NULL; return; } - if(dlm) { - mvertbase= dlm->mvert; - mfacebase= dlm->mface; - totface= dlm->totface; - totvert= dlm->totvert; + /* 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; iflag & PAF_TRAND)==0) { + jitlevel= paf->userjit; + + 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; + } + + 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(totvert==0) { - mvertbase= me->mvert; - mfacebase= me->mface; - totface= me->totface; - totvert= me->totvert; - } - - if(totface==0 || nrco); - VECCOPY(no, mvert->no); + if(paf->flag & PAF_TRAND) { + u= trands[2*partnr]; + v= trands[2*partnr+1]; } else { - - nr-= totvert; + /* jittered distribution gets fixed random offset */ + if(subnr>=jitlevel) { + int jitrand= (subnr/jitlevel) % JIT_RAND; - if(jit==0) { - jitlevel= nr/totface; - if(jitlevel==0) jitlevel= 1; - if(jitlevel>100) jitlevel= 100; - - jit= MEM_callocN(2+ jitlevel*2*sizeof(float), "jit"); - init_mv_jit(jit, jitlevel,seed2); - - } - - curjit= nr/totface; - curjit= curjit % jitlevel; - - curface= nr % totface; - - mface= mfacebase; - mface+= curface; - - v1= (mvertbase+(mface->v1))->co; - v2= (mvertbase+(mface->v2))->co; - n1= (mvertbase+(mface->v1))->no; - n2= (mvertbase+(mface->v2))->no; - v3= (mvertbase+(mface->v3))->co; - n3= (mvertbase+(mface->v3))->no; - if(mface->v4==0) { - v4= (mvertbase+(mface->v1))->co; - n4= (mvertbase+(mface->v1))->no; + 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 { - v4= (mvertbase+(mface->v4))->co; - n4= (mvertbase+(mface->v4))->no; + u= jit[2*subnr]; + v= jit[2*subnr+1]; } - - u= jit[2*curjit]; - v= jit[2*curjit+1]; - - co[0]= (float)((1.0-u)*(1.0-v)*v1[0] + (1.0-u)*(v)*v2[0] + (u)*(v)*v3[0] + (u)*(1.0-v)*v4[0]); - co[1]= (float)((1.0-u)*(1.0-v)*v1[1] + (1.0-u)*(v)*v2[1] + (u)*(v)*v3[1] + (u)*(1.0-v)*v4[1]); - co[2]= (float)((1.0-u)*(1.0-v)*v1[2] + (1.0-u)*(v)*v2[2] + (u)*(v)*v3[2] + (u)*(1.0-v)*v4[2]); + } + + v1= (mvert+(mface->v1))->co; + v2= (mvert+(mface->v2))->co; + v3= (mvert+(mface->v3))->co; + n1= (mvert+(mface->v1))->no; + n2= (mvert+(mface->v2))->no; + n3= (mvert+(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); - no[0]= (short)((1.0-u)*(1.0-v)*n1[0] + (1.0-u)*(v)*n2[0] + (u)*(v)*n3[0] + (u)*(1.0-v)*n4[0]); - no[1]= (short)((1.0-u)*(1.0-v)*n1[1] + (1.0-u)*(v)*n2[1] + (u)*(v)*n3[1] + (u)*(1.0-v)*n4[1]); - no[2]= (short)((1.0-u)*(1.0-v)*n1[2] + (1.0-u)*(v)*n2[2] + (u)*(v)*n3[2] + (u)*(1.0-v)*n4[2]); + v4= (mvert+(mface->v4))->co; + n4= (mvert+(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]; + + no[0]= (short)(mumv*n1[0] + muv*n2[0] + uv*n3[0] + umv*n4[0]); + no[1]= (short)(mumv*n1[1] + muv*n2[1] + uv*n3[1] + umv*n4[1]); + no[2]= (short)(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]= (short)(n1[0] + u*(n3[0]-n1[0]) + v*(n2[0]-n1[0])); + no[1]= (short)(n1[1] + u*(n3[1]-n1[1]) + v*(n2[1]-n1[1])); + no[2]= (short)(n1[2] + u*(n3[2]-n1[2]) + v*(n2[2]-n1[2])); } } +/* 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; +} + +/* 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; + } + + return tweight; +} + +/* helper function for build_particle_system() */ +static void make_weight_tables(PartEff *paf, Mesh *me, int totpart, MVert *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; advert+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; aflag & 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; av4) + 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; av4) + 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; + } + } +} + +/* for paf start to end, store all matrices for objects */ +typedef struct pMatrixCache { + float obmat[4][4]; + float imat[3][3]; +} pMatrixCache; + +static pMatrixCache *cache_object_matrices(Object *ob, int start, int end) +{ + pMatrixCache *mcache, *mc; + Object *par; + float framelenold, sfrao; + int cfrao; + + 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; + sfrao= ob->sf; + ob->sf= 0.0f; + + for(G.scene->r.cfra= start; G.scene->r.cfra<=end; G.scene->r.cfra++, mc++) { + + par= ob; + while(par) { + par->ctime= -1234567.0; /* hrms? */ + do_ob_key(par); + if(par->type==OB_ARMATURE) { + do_all_pose_actions(par); // only does this object actions + where_is_pose(par); + } + par= par->parent; + } + + where_is_object(ob); + 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= sfrao; + + /* restore hierarchy */ + par= ob; + while(par) { + /* do not do ob->ipo: keep insertkey */ + par->ctime= -1234567.0; /* hrms? */ + do_ob_key(par); + + if(par->type==OB_ARMATURE) { + do_all_pose_actions(par); // only does this object actions + where_is_pose(par); + } + par= par->parent; + } + + where_is_object(ob); + + return mcache; +} + +/* 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; - Base *base; - Object *par; PartEff *paf; Particle *pa; Mesh *me; - MTex *mtexmove=0; + Base *base; + MTex *mtexmove=0, *mtextime=0; Material *ma; DispListMesh *dlm; - int dmNeedsFree; + MFace *facelist= NULL; + MVert *vertlist= NULL; DerivedMesh *dm; - float framelenont, ftime, dtime, force[3], imat[3][3], vec[3]; - float fac, prevobmat[4][4], sfraont, co[3]; - int deform=0, a, cur, cfraont, cfralast, totpart, totvert; + pMatrixCache *mcache=NULL, *mcnow, *mcprev; + double startseconds= PIL_check_seconds_timer(); + float ftime, dtime, force[3], vec[3]; + float fac, co[3]; + float *voweights= NULL, *foweights= NULL, maxw=1.0f; + int deform=0, a, totpart, paf_sta, paf_end; + int dmNeedsFree, waitcursor_set= 0, totvert, totface, curface, curvert; short no[3]; - + + /* return conditions */ if(ob->type!=OB_MESH) return; me= ob->data; - if(me->totvert==0) return; - - ma= give_current_material(ob, 1); - if(ma) { - mtexmove= ma->mtex[7]; - } paf= give_parteff(ob); if(paf==NULL) return; - - waitcursor(1); - - disable_speed_curve(1); - - /* generate all particles */ - if(paf->keys) MEM_freeN(paf->keys); + if(paf->keys) MEM_freeN(paf->keys); /* free as early as possible, for returns */ paf->keys= NULL; + + if(paf->end < paf->sta) return; + + if( (paf->flag & PAF_OFACE) && (paf->flag & PAF_FACE)==0) return; + + if(me->totvert==0) return; + + /* this call returns NULL during editmode, just ignore it and + * particles should be recalc'd on exit. */ + dm = mesh_get_derived_deform(ob, &dmNeedsFree); + if (dm==NULL) + 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]; + } + + disable_speed_curve(1); /* check this... */ + + /* initialize particles */ new_particle(paf); /* reset deflector cache, sumohandle is free, but its still sorta abuse... (ton) */ - for(base= G.scene->base.first; base; base= base->next) { + for(base= G.scene->base.first; base; base= base->next) base->object->sumohandle= NULL; - } - - cfraont= G.scene->r.cfra; - cfralast= -1000; - framelenont= G.scene->r.framelen; - G.scene->r.framelen= 1.0; - sfraont= ob->sf; - ob->sf= 0.0; + /* 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? */ - totpart= paf->totpart; + totpart= (R.flag & R_RENDERING)?paf->totpart:(paf->disp*paf->totpart)/100; for(a=0; amult[a]!=0.0) { - /* interessant formula! this way after 'x' generations the total is paf->totpart */ + /* interesting formula! this way after 'x' generations the total is paf->totpart */ totpart= (int)(totpart / (1.0+paf->mult[a]*paf->child[a])); } else break; } - if (paf->flag & PAF_STATIC) { - ftime = cfraont; - dtime = 0; - } else { - ftime= paf->sta; - dtime= (paf->end - paf->sta)/totpart; - } - - /* this call returns NULL during editmode, just ignore it and - * particles should be recalc'd on exit. - */ - dm = mesh_get_derived_final(ob, &dmNeedsFree); - if (!dm) { - waitcursor(0); - return; - } - - /* WARNING!!!! pushdata and popdata actually copy object memory!!!! - * Changes between these calls will be lost!!! - */ - - /* remember full hierarchy */ - par= ob; - while(par) { - pushdata(par, sizeof(Object)); - par= par->parent; - } - - /* for static particles, calculate system on current frame */ + /* for static particles, calculate system on current frame (? ton) */ if(ma) do_mat_ipo(ma); - - /* set it all at first frame */ - G.scene->r.cfra= cfralast= (int)floor(ftime); - par= ob; - while(par) { - /* do_ob_ipo(par); */ - do_ob_key(par); - par= par->parent; - } - /* matrix stuff for static too */ + /* matrix invert for static too */ Mat4Invert(ob->imat, ob->obmat); - if((paf->flag & PAF_STATIC)==0) { - if(ma) do_mat_ipo(ma); // nor for static - - where_is_object(ob); - Mat4CpyMat4(prevobmat, ob->obmat); - Mat3CpyMat4(imat, ob->imat); - } - else { - Mat4One(prevobmat); - Mat3One(imat); - } - + /* new random generator */ rng = rng_new(paf->seed); /* otherwise it goes way too fast */ @@ -1236,142 +1612,223 @@ void build_particle_system(Object *ob) if(deform) init_latt_deform(ob->parent, 0); } - /* init */ - + /* init geometry */ dlm = dm->convertToDispListMesh(dm, 1); - totvert = dlm->totvert; - - give_mesh_mvert(me, dlm, totpart, co, no, paf->seed); - if(G.f & G_DEBUG) { - printf("\n"); - printf("Calculating particles......... \n"); + /* subsurfs don't have vertexgroups, so we need to use me->mvert in that case */ + if(paf->vertgroup && me->dvert && (dlm->totvert != me->totvert)) { + vertlist= me->mvert; + facelist= me->mface; + totvert= me->totvert; + totface= me->totface; } + else { + vertlist= dlm->mvert; + facelist= dlm->mface; + totvert= dlm->totvert; + totface= dlm->totface; + } + /* if vertexweights or even distribution, it makes weight tables, also checks where it emits from */ + make_weight_tables(paf, me, totpart, vertlist, totvert, facelist, totface, &voweights, &foweights); + + /* 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, vertlist, 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 0.5) { + waitcursor(1); + waitcursor_set= 1; + } + } + pa= new_particle(paf); pa->time= ftime; - - if(G.f & G_DEBUG) { - int b, c; + + /* get coordinates from faces, only when vertices set to zero */ + if(totvert==0 && totface) { + int curjit; - c = totpart/100; - if (c==0){ - c = 1; - } - - b=(a%c); - if (b==0) { - printf("\r Particle: %d / %d ", a, totpart); - fflush(stdout); - } - } - /* set ob at correct time */ - - if((paf->flag & PAF_STATIC)==0) { - - cur= (int)floor(ftime) + 1 ; /* + 1 has a reason: (obmat/prevobmat) otherwise comet-tails start too late */ - if(cfralast != cur) { - G.scene->r.cfra= cfralast= cur; - - /* added later: blur? */ - bsystem_time(ob, ob->parent, (float)G.scene->r.cfra, 0.0); - - par= ob; - while(par) { - /* do_ob_ipo(par); */ - par->ctime= -1234567.0; - do_ob_key(par); - if(par->type==OB_ARMATURE) { - do_all_pose_actions(par); // only does this object actions - where_is_pose(par); + /* 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 && curfaceparent; + foweights[curface] += remainder; + maxw= (paf->end-paf->sta)/foweights[curface]; } - if(ma) do_mat_ipo(ma); - Mat4CpyMat4(prevobmat, ob->obmat); - where_is_object(ob); - Mat4Invert(ob->imat, ob->obmat); - Mat3CpyMat4(imat, ob->imat); + + if(foweights[curface]==0.0f) + break; /* WARN skips here out of particle generating */ + else { + if(foweights[curface] > 1.0f) + foweights[curface] -= 1.0f; + + curjit= (int) foweights[curface]; + give_mesh_particle_coord(paf, vertlist, 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, vertlist, facelist+curface, a, curjit, co, no); } } - /* get coordinates */ - if(paf->flag & PAF_FACE) give_mesh_mvert(me, dlm, a, co, no, paf->seed); - else { - if (totvert) { - VECCOPY(co, dlm->mvert[a%totvert].co); - VECCOPY(no, dlm->mvert[a%totvert].no); - } else { - co[0] = co[1] = co[2] = 0.0f; - no[0] = no[1] = no[2] = 0; + /* 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 && curvertend-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; + } + + VECCOPY(co, vertlist[curvert].co); + VECCOPY(no, vertlist[curvert].no); } VECCOPY(pa->co, co); - if(paf->flag & PAF_STATIC); - else { - Mat4MulVecfl(ob->obmat, pa->co); + /* dynamic options */ + if((paf->flag & PAF_STATIC)==0) { + int cur; + + /* 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); + } + + /* 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 + 1; + + if(cur > paf_sta) mcprev= mcnow-1; + else mcprev= mcache; + + /* move to global space */ + Mat4MulVecfl(mcnow->obmat, pa->co); VECCOPY(vec, co); - Mat4MulVecfl(prevobmat, vec); + 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= (ftime- (float)floor(ftime)); + 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) { - /* transpose ! */ - vec[0]= imat[0][0]*no[0] + imat[0][1]*no[1] + imat[0][2]*no[2]; - vec[1]= imat[1][0]*no[0] + imat[1][1]*no[1] + imat[1][2]*no[2]; - vec[2]= imat[2][0]*no[0] + imat[2][1]*no[1] + imat[2][2]*no[2]; - - Normalise(vec); - VecMulf(vec, paf->normfac); - VECADD(pa->no, pa->no, vec); + /* start speed: normal */ + if(paf->normfac!=0.0) { + /* imat is transpose ! */ + VECCOPY(vec, no); + Mat3MulVecfl(mcnow->imat, vec); + + Normalise(vec); + VecMulf(vec, paf->normfac); + VECADD(pa->no, pa->no, vec); + } } + else { + if(paf->normfac!=0.0) { + VECCOPY(pa->no, no); + Normalise(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= 1; + pa->mat_nr= paf->omat; - make_particle_keys(rng, ob, 0, a, paf, pa, force, deform, mtexmove, ob->lay, cfraont); + make_particle_keys(rng, ob, 0, a, paf, pa, force, deform, mtexmove, ob->lay); } - if(G.f & G_DEBUG) { - printf("\r Particle: %d / %d \n", totpart, totpart); - fflush(stdout); - } + /* free stuff */ + give_mesh_particle_coord(NULL, NULL, NULL, 0, 0, NULL, NULL); + if(voweights) MEM_freeN(voweights); + if(foweights) MEM_freeN(foweights); + if(mcache) MEM_freeN(mcache); + if(deform) end_latt_deform(); - - /* restore */ - G.scene->r.cfra= cfraont; - G.scene->r.framelen= framelenont; - give_mesh_mvert(0, 0, 0, 0, 0,paf->seed); - - /* put hierarchy back */ - par= ob; - while(par) { - popfirst(par); - /* do not do ob->ipo: keep insertkey */ - do_ob_key(par); - - if(par->type==OB_ARMATURE) { - do_all_pose_actions(par); // only does this object actions - where_is_pose(par); - } - par= par->parent; - } - + /* reset deflector cache */ for(base= G.scene->base.first; base; base= base->next) { if(base->object->sumohandle) { @@ -1380,10 +1837,6 @@ void build_particle_system(Object *ob) } } - /* restore: AFTER popfirst */ - ob->sf= sfraont; - - if(ma) do_mat_ipo(ma); // set back on current time disable_speed_curve(0); waitcursor(0); diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 10395326357..38732377e29 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -346,11 +346,11 @@ int sb_detect_collision(float opco[3], float facenormal[3], float *damp, { Base *base; Object *ob; - int a, deflected=0; float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3],d_nvect[3], dv1[3], dv2[3], facedist,n_mag,t,force_mag_norm, innerfacethickness = -0.5f, outerfacethickness = 0.2f, ee = 5.0f, ff = 0.1f, fa; + int a, deflected=0; base= G.scene->base.first; while (base) { @@ -495,29 +495,27 @@ static int sb_deflect_face(Object *ob,float *actpos, float *futurepos,float *col { int deflected; float s_actpos[3], s_futurepos[3]; + VECCOPY(s_actpos,actpos); if(futurepos) - VECCOPY(s_futurepos,futurepos); + VECCOPY(s_futurepos,futurepos); + deflected= sb_detect_collision(s_actpos, facenormal, cf, force , ob->lay, ob); return(deflected); - } -#define USES_FIELD 1 -#define USES_DEFLECT 2 static int is_there_deflection(unsigned int layer) { Base *base; - int retval= 0; for(base = G.scene->base.first; base; base= base->next) { if( (base->lay & layer) && base->object->pd) { - if(base->object->pd->forcefield) retval |= USES_FIELD; - if(base->object->pd->deflect) retval |= USES_DEFLECT; + if(base->object->pd->deflect) + return 1; } } - return retval; + return 0; } static void softbody_calc_forces(Object *ob, float forcetime) @@ -529,10 +527,10 @@ static void softbody_calc_forces(Object *ob, float forcetime) BodyPoint *bp; BodyPoint *bproot; BodySpring *bs; - float iks, ks, kd, gravity, actspringlen, forcefactor, sd[3], - fieldfactor = 1000.0f, - windfactor = 250.0f; - int a, b, do_effector; + ListBase *do_effector; + float iks, ks, kd, gravity, actspringlen, forcefactor, sd[3]; + float fieldfactor = 1000.0f, windfactor = 250.0f; + int a, b, do_deflector; /* clear forces */ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { @@ -540,8 +538,11 @@ static void softbody_calc_forces(Object *ob, float forcetime) } gravity = sb->grav * sb_grav_force_scale(ob); + /* check! */ - do_effector= is_there_deflection(ob->lay); + do_deflector= is_there_deflection(ob->lay); + do_effector= pdInitEffectors(ob->lay); + iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ bproot= sb->bpoint; /* need this for proper spring addressing */ @@ -581,14 +582,15 @@ static void softbody_calc_forces(Object *ob, float forcetime) bp->force[2]-= gravity*sb->nodemass; /* individual mass of node here */ /* particle field & vortex */ - if(do_effector & USES_FIELD) { + if(do_effector) { float force[3]= {0.0f, 0.0f, 0.0f}; float speed[3]= {0.0f, 0.0f, 0.0f}; float eval_sb_fric_force_scale = sb_fric_force_scale(ob); // just for calling functio once - pdDoEffector(bp->pos, force, speed, (float)G.scene->r.cfra, ob->lay,PE_WIND_AS_SPEED); - // note: now we have wind as motion of media, so we can do anisotropic stuff here, - // if we had vertex normals here(BM) + pdDoEffectors(do_effector, bp->pos, force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); + + /* note: now we have wind as motion of media, so we can do anisotropic stuff here, */ + /* if we had vertex normals here(BM) */ /* apply forcefield*/ VecMulf(force,fieldfactor* eval_sb_fric_force_scale); VECADD(bp->force, bp->force, force); @@ -616,7 +618,7 @@ static void softbody_calc_forces(Object *ob, float forcetime) yes, constraints and collision stuff should go here too (read baraff papers on that!) */ /* moving collision targets */ - if(do_effector & USES_DEFLECT) { + if(do_deflector) { float defforce[3] = {0.0f,0.0f,0.0f}, collisionpos[3],facenormal[3], cf = 1.0f; kd = 1.0f; @@ -689,6 +691,11 @@ static void softbody_calc_forces(Object *ob, float forcetime) }/*any edges*/ }/*omit on snap */ }/*loop all bp's*/ + + /* cleanup */ + if(do_effector) + pdEndEffectors(do_effector); + } static void softbody_apply_forces(Object *ob, float forcetime, int mode, float *err) @@ -701,11 +708,9 @@ static void softbody_apply_forces(Object *ob, float forcetime, int mode, float * float dx[3],dv[3]; float timeovermass; float maxerr = 0.0; - int a, do_effector; + int a; forcetime *= sb_time_scale(ob); - /* check! */ - do_effector= is_there_deflection(ob->lay); // claim a minimum mass for vertex if (sb->nodemass > 0.09999f) timeovermass = forcetime/sb->nodemass; @@ -771,6 +776,7 @@ static void softbody_apply_forces(Object *ob, float forcetime, int mode, float * else { VECADD(bp->pos, bp->pos, dx);} }//snap } //for + if (err){ /* so step size will be controlled by biggest difference in slope */ *err = maxerr; } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index ab7352e4a5f..f84f72da494 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4909,6 +4909,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) for(ob=main->object.first; ob; ob= ob->id.next) { ModifierData *md; + PartEff *paf; for (md=ob->modifiers.first; md; md=md->next) { if (md->type==eModifierType_Subsurf) { @@ -4959,6 +4960,16 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } } + + paf = give_parteff(ob); + if (paf) { + if(paf->disp == 0) + paf->disp = 100; + if(paf->speedtex == 0) + paf->speedtex = 8; + if(paf->omat == 0) + paf->omat = 1; + } } for(arm=main->armature.first; arm; arm= arm->id.next) { diff --git a/source/blender/include/BIF_butspace.h b/source/blender/include/BIF_butspace.h index 4dda9f6fb43..f5ae79fcd80 100644 --- a/source/blender/include/BIF_butspace.h +++ b/source/blender/include/BIF_butspace.h @@ -44,8 +44,6 @@ extern void redraw_test_buttons(struct Object *new); /* buttons_editing.c */ extern void validate_editbonebutton_cb(void *bonev, void *namev); -extern void autocomplete_bone(char *str, void *arg_v); - /* buts->mainb old */ #define BUTS_VIEW 0 diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index e497fe48c77..e6e291fb285 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -65,6 +65,8 @@ extern void physics_panels(void); extern void do_object_panels(unsigned short event); extern void do_constraintbuts(unsigned short event); extern void object_panel_constraint(char *context); +extern void autocomplete_bone(char *str, void *arg_v); +extern void autocomplete_vgroup(char *str, void *arg_v); /* effects */ extern void effects_panels(void); @@ -625,6 +627,7 @@ enum { #define B_EFFECT_DEP 3413 #define B_FIELD_DEP 3414 #define B_FIELD_CHANGE 3415 +#define B_PAF_SET_VG 3416 #define B_MODIFIER_BUTS 3600 diff --git a/source/blender/makesdna/DNA_effect_types.h b/source/blender/makesdna/DNA_effect_types.h index 299756edfe1..084ad9ac82f 100644 --- a/source/blender/makesdna/DNA_effect_types.h +++ b/source/blender/makesdna/DNA_effect_types.h @@ -38,11 +38,27 @@ #define PAF_MAXMULT 4 - /* paf->flag (keep bit 0 free for compatibility) */ +/* paf->flag (keep bit 0 free for compatibility) */ #define PAF_BSPLINE 2 #define PAF_STATIC 4 #define PAF_FACE 8 #define PAF_ANIMATED 16 + /* show particles before they're emitted*/ +#define PAF_UNBORN 32 + /* emit only from faces*/ +#define PAF_OFACE 64 + /* show emitter (don't hide actual mesh)*/ +#define PAF_SHOWE 128 + /* true random emit from faces (not just ordered jitter)*/ +#define PAF_TRAND 256 + /* even distribution in face emission based on face areas*/ +#define PAF_EDISTR 512 + /*show particles after they've died*/ +#define PAF_DIED 2048 + + +/*paf->flag2 for pos/neg paf->flag2neg*/ +#define PAF_TEXTIME 1 /*texture timing*/ /* eff->type */ #define EFF_BUILD 0 @@ -91,7 +107,7 @@ typedef struct Particle { typedef struct PartEff { struct PartEff *next, *prev; - short type, flag, buttype, stype; + short type, flag, buttype, stype, vertgroup, userjit; float sta, end, lifetime; int totpart, totkey, seed; @@ -105,8 +121,10 @@ typedef struct PartEff { float mult[4], life[4]; short child[4], mat[4]; short texmap, curmult; - short staticstep, pad; + short staticstep, omat, timetex, speedtex, flag2, flag2neg; + short disp, pad; + char vgroupname[32]; Particle *keys; } PartEff; diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h index 3396c59a53a..60a60cf22f3 100644 --- a/source/blender/makesdna/DNA_object_force.h +++ b/source/blender/makesdna/DNA_object_force.h @@ -104,6 +104,7 @@ typedef struct SoftBody { #define PFIELD_VORTEX 2 #define PFIELD_MAGNET 3 #define PFIELD_WIND 4 +#define PFIELD_GUIDE 5 /* pd->flag: various settings */ #define PFIELD_USEMAX 1 diff --git a/source/blender/renderconverter/intern/convertBlenderScene.c b/source/blender/renderconverter/intern/convertBlenderScene.c index ddc97c1c0cb..37d256e261a 100644 --- a/source/blender/renderconverter/intern/convertBlenderScene.c +++ b/source/blender/renderconverter/intern/convertBlenderScene.c @@ -816,7 +816,7 @@ static void render_particle_system(Object *ob, PartEff *paf) int a, mat_nr=1, seed; pa= paf->keys; - if(pa==NULL) { + if(pa==NULL || paf->disp!=100) { build_particle_system(ob); pa= paf->keys; if(pa==NULL) return; @@ -839,65 +839,74 @@ static void render_particle_system(Object *ob, PartEff *paf) for(a=0; atotpart; a++, pa+=paf->totkey) { - if(ctime > pa->time) { - if(ctime < pa->time+pa->lifetime) { - - /* watch it: also calculate the normal of a particle */ - if(paf->stype==PAF_VECT || ma->mode & MA_HALO_SHADE) { - where_is_particle(paf, pa, ctime, vec); - MTC_Mat4MulVecfl(R.viewmat, vec); - where_is_particle(paf, pa, ctime+1.0, vec1); - MTC_Mat4MulVecfl(R.viewmat, vec1); - } - else { - where_is_particle(paf, pa, ctime, vec); - MTC_Mat4MulVecfl(R.viewmat, vec); - } - - if(pa->mat_nr != mat_nr) { - mat_nr= pa->mat_nr; - ma= give_render_material(ob, mat_nr); - } - - if(ma->ipo) { - /* correction for lifetime */ - ptime= 100.0*(ctime-pa->time)/pa->lifetime; - calc_ipo(ma->ipo, ptime); - execute_ipo((ID *)ma, ma->ipo); - } - - hasize= ma->hasize; - - if(ma->mode & MA_HALOPUNO) { - xn= pa->no[0]; - yn= pa->no[1]; - zn= pa->no[2]; - - /* transpose ! */ - nor[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; - nor[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; - nor[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; - Normalise(nor); - - VECCOPY(view, vec); - Normalise(view); - - zn= nor[0]*view[0]+nor[1]*view[1]+nor[2]*view[2]; - if(zn>=0.0) hasize= 0.0; - else hasize*= zn*zn*zn*zn; - } - - if(paf->stype==PAF_VECT) har= RE_inithalo(ma, vec, vec1, pa->co, hasize, paf->vectsize, seed); - else { - har= RE_inithalo(ma, vec, NULL, pa->co, hasize, 0.0, seed); - if(har && ma->mode & MA_HALO_SHADE) { - VecSubf(har->no, vec, vec1); - Normalise(har->no); - } - } - if(har) har->lay= ob->lay; + if((paf->flag & PAF_UNBORN)==0) { + if(ctime < pa->time) + { + seed++; + continue; } } + if((paf->flag & PAF_DIED)==0) { + if(ctime > pa->time+pa->lifetime) + { + seed++; + continue; + } + } + /* watch it: also calculate the normal of a particle */ + if(paf->stype==PAF_VECT || ma->mode & MA_HALO_SHADE) { + where_is_particle(paf, pa, ctime, vec); + MTC_Mat4MulVecfl(R.viewmat, vec); + where_is_particle(paf, pa, ctime+1.0, vec1); + MTC_Mat4MulVecfl(R.viewmat, vec1); + } + else { + where_is_particle(paf, pa, ctime, vec); + MTC_Mat4MulVecfl(R.viewmat, vec); + } + + if(pa->mat_nr != mat_nr) { + mat_nr= pa->mat_nr; + ma= give_render_material(ob, mat_nr); + } + + if(ma->ipo) { + /* correction for lifetime */ + ptime= 100.0*(ctime-pa->time)/pa->lifetime; + calc_ipo(ma->ipo, ptime); + execute_ipo((ID *)ma, ma->ipo); + } + + hasize= ma->hasize; + + if(ma->mode & MA_HALOPUNO) { + xn= pa->no[0]; + yn= pa->no[1]; + zn= pa->no[2]; + + /* transpose ! */ + nor[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; + nor[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; + nor[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; + Normalise(nor); + + VECCOPY(view, vec); + Normalise(view); + + zn= nor[0]*view[0]+nor[1]*view[1]+nor[2]*view[2]; + if(zn>=0.0) hasize= 0.0; + else hasize*= zn*zn*zn*zn; + } + + if(paf->stype==PAF_VECT) har= RE_inithalo(ma, vec, vec1, pa->co, hasize, paf->vectsize, seed); + else { + har= RE_inithalo(ma, vec, NULL, pa->co, hasize, 0.0, seed); + if(har && ma->mode & MA_HALO_SHADE) { + VecSubf(har->no, vec, vec1); + Normalise(har->no); + } + } + if(har) har->lay= ob->lay; seed++; } @@ -907,6 +916,10 @@ static void render_particle_system(Object *ob, PartEff *paf) if(ma) do_mat_ipo(ma); } + if(paf->disp!=100) { + MEM_freeN(paf->keys); + paf->keys= NULL; + } } @@ -1005,7 +1018,7 @@ static void render_static_particle_system(Object *ob, PartEff *paf) int a, mat_nr=1, seed; pa= paf->keys; - if(pa==NULL || (paf->flag & PAF_ANIMATED)) { + if(pa==NULL || (paf->flag & PAF_ANIMATED) || paf->disp!=100) { build_particle_system(ob); pa= paf->keys; if(pa==NULL) return; @@ -1139,6 +1152,11 @@ static void render_static_particle_system(Object *ob, PartEff *paf) seed++; if(orco) orco+=3; } + + if(paf->disp!=100) { + MEM_freeN(paf->keys); + paf->keys= NULL; + } } @@ -1349,7 +1367,7 @@ static void init_render_mesh(Object *ob) /* warning; build_particle_system does modifier calls itself */ if(paf->flag & PAF_STATIC) render_static_particle_system(ob, paf); else render_particle_system(ob, paf); - return; + if((paf->flag & PAF_SHOWE)==0) return; } MTC_Mat4MulMat4(mat, ob->obmat, R.viewmat); diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 46c6b1b7959..77570ed688f 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -1271,11 +1271,13 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco } else if (md->type==eModifierType_Lattice) { LatticeModifierData *lmd = (LatticeModifierData*) md; uiDefIDPoinBut(block, modifier_testLatticeObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &lmd->object, "Lattice object to deform with"); - uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &lmd->name, 0.0, 31.0, 0, 0, "Vertex Group name"); + but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &lmd->name, 0.0, 31.0, 0, 0, "Vertex Group name"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)lmd->object); } else if (md->type==eModifierType_Curve) { CurveModifierData *cmd = (CurveModifierData*) md; uiDefIDPoinBut(block, modifier_testCurveObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &cmd->object, "Curve object to deform with"); - uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &cmd->name, 0.0, 31.0, 0, 0, "Vertex Group name"); + but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &cmd->name, 0.0, 31.0, 0, 0, "Vertex Group name"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)cmd->object); } else if (md->type==eModifierType_Build) { BuildModifierData *bmd = (BuildModifierData*) md; uiDefButF(block, NUM, B_MODIFIER_RECALC, "Start:", lx, (cy-=19), buttonWidth,19, &bmd->start, 1.0, MAXFRAMEF, 100, 0, "Specify the start frame of the effect"); @@ -1291,7 +1293,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco uiDefButBitS(block, TOG, MOD_MIR_CLIPPING, B_MODIFIER_RECALC, "Do Clipping", lx+60, cy, buttonWidth-60,19, &mmd->flag, 1, 2, 0, 0, "Prevents during Transform vertices to go through Mirror"); } else if (md->type==eModifierType_Decimate) { DecimateModifierData *dmd = (DecimateModifierData*) md; - uiDefButF(block, NUM, B_MODIFIER_RECALC, "Percent:", lx,(cy-=19),buttonWidth,19, &dmd->percent, 0.0, 1.0, 0, 0, "Defines the percentage of triangles to reduce to"); + uiDefButF(block, NUM, B_MODIFIER_RECALC, "Percent:", lx,(cy-=19),buttonWidth,19, &dmd->percent, 0.0, 1.0, 10, 0, "Defines the percentage of triangles to reduce to"); sprintf(str, "Face Count: %d", dmd->faceCount); uiDefBut(block, LABEL, 1, str, lx, (cy-=19), 160,19, NULL, 0.0, 0.0, 0, 0, "Displays the current number of faces in the decimated mesh"); } else if (md->type==eModifierType_Wave) { @@ -1323,8 +1325,10 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco uiDefButF(block, NUM, B_MODIFIER_RECALC, "Falloff: ", lx, (cy-=19), buttonWidth,19, &hmd->falloff, 0.0, 100.0, 100, 0, "If not zero, the distance from hook where influence ends"); uiDefButF(block, NUMSLI, B_MODIFIER_RECALC, "Force: ", lx, (cy-=19), buttonWidth,19, &hmd->force, 0.0, 1.0, 100, 0, "Set relative force of hook"); uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &hmd->object, "Parent Object for hook, also recalculates and clears offset"); - if(hmd->indexar==NULL) - uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &hmd->name, 0.0, 31.0, 0, 0, "Vertex Group name"); + if(hmd->indexar==NULL) { + but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &hmd->name, 0.0, 31.0, 0, 0, "Vertex Group name"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)hmd->object); + } uiBlockBeginAlign(block); but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Reset", lx, (cy-=19), 80,19, NULL, 0.0, 0.0, 0, 0, "Recalculate and clear offset (transform) of hook"); uiButSetFunc(but, modifiers_clearHookOffset, ob, md); @@ -3410,6 +3414,7 @@ static void editing_panel_links(Object *ob) defGroup = BLI_findlink(&ob->defbase, ob->actdef-1); but= uiDefBut(block, TEX, REDRAWBUTSEDIT,"", 161,132,140-18,21, defGroup->name, 0, 31, 0, 0, "Displays current vertex group name. Click to change. (Match bone name for deformation.)"); uiButSetFunc(but, verify_vertexgroup_name_func, defGroup, NULL); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob); uiDefButF(block, NUM, REDRAWVIEW3D, "Weight:", 143, 111, 140, 21, &editbutvweight, 0, 1, 10, 0, "Sets the current vertex group's bone deformation strength"); } diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 43897b2f0bd..c12fd3165df 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -114,6 +114,7 @@ #include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_curve.h" +#include "BKE_deform.h" #include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_effect.h" @@ -130,9 +131,11 @@ #include "BKE_texture.h" #include "BKE_utildefines.h" #include "BKE_DerivedMesh.h" + #include "LBM_fluidsim.h" #include "BIF_editconstraint.h" +#include "BIF_editdeform.h" #include "BSE_editipo.h" #include "BSE_edit.h" @@ -447,7 +450,43 @@ void autocomplete_bone(char *str, void *arg_v) } } - +/* autocomplete callback for ID buttons */ +void autocomplete_vgroup(char *str, void *arg_v) +{ + Object *ob= (Object *)arg_v; + char truncate[40]= {0}; + + if(ob==NULL) return; + + /* search if str matches the beginning of an ID struct */ + if(str[0]) { + bDeformGroup *dg; + + for(dg= ob->defbase.first; dg; dg= dg->next) { + int a; + + for(a=0; a<31; a++) { + if(str[a]==0 || str[a]!=dg->name[a]) + break; + } + /* found a match */ + if(str[a]==0) { + /* first match */ + if(truncate[0]==0) + BLI_strncpy(truncate, dg->name, 32); + else { + /* remove from truncate what is not in bone->name */ + for(a=0; a<31; a++) { + if(truncate[a]!=dg->name[a]) + truncate[a]= 0; + } + } + } + } + if(truncate[0]) + BLI_strncpy(str, truncate, 32); + } +} static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, short *xco, short *yco) { @@ -1485,7 +1524,7 @@ void do_effects_panels(unsigned short event) Object *ob; Base *base; Effect *eff, *effn; - int type; + PartEff *paf; ob= OBACT; @@ -1506,11 +1545,12 @@ void do_effects_panels(unsigned short event) else copy_act_effect(ob); } + DAG_scene_sort(G.scene); BIF_undo_push("New effect"); allqueue(REDRAWBUTSOBJECT, 0); break; case B_DELEFFECT: - if(ob==0 || ob->type!=OB_MESH) break; + if(ob==NULL || ob->type!=OB_MESH) break; eff= ob->effect.first; while(eff) { effn= eff->next; @@ -1555,25 +1595,6 @@ void do_effects_panels(unsigned short event) } allqueue(REDRAWBUTSOBJECT, 0); break; - case B_CHANGEEFFECT: - if(ob==0 || ob->type!=OB_MESH) break; - eff= ob->effect.first; - while(eff) { - if(eff->flag & SELECT) { - if(eff->type!=eff->buttype) { - BLI_remlink(&ob->effect, eff); - type= eff->buttype; - free_effect(eff); - eff= add_effect(type); - BLI_addtail(&ob->effect, eff); - } - break; - } - eff= eff->next; - } - allqueue(REDRAWVIEW3D, 0); - allqueue(REDRAWBUTSOBJECT, 0); - break; case B_EFFECT_DEP: DAG_scene_sort(G.scene); /* no break, pass on */ @@ -1589,9 +1610,30 @@ void do_effects_panels(unsigned short event) allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWBUTSOBJECT, 0); break; + case B_PAF_SET_VG: + + paf= give_parteff(ob); + if(paf) { + bDeformGroup *dg= get_named_vertexgroup(ob, paf->vgroupname); + if(dg) + paf->vertgroup= get_defgroup_num(ob, dg)+1; + else + paf->vertgroup= 0; + + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + } + break; case B_FIELD_DEP: DAG_scene_sort(G.scene); + DAG_object_flush_update(G.scene, ob, OB_RECALC_OB); + if(ob->type==OB_CURVE && ob->pd->forcefield==PFIELD_GUIDE) { + Curve *cu= ob->data; + cu->flag |= (CU_PATH|CU_3D); + DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA); + } allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWBUTSOBJECT, 0); break; case B_FIELD_CHANGE: DAG_object_flush_update(G.scene, ob, OB_RECALC_OB); @@ -1614,7 +1656,6 @@ void do_effects_panels(unsigned short event) } allqueue(REDRAWVIEW3D, 0); break; - default: if(event>=B_SELEFFECT && eventuiblocks, "object_panel_fields", UI_EMBOSS, UI_HELV, curarea->win); - if(uiNewPanel(curarea, block, "Fields and Defection", "Physics", 420, 0, 318, 204)==0) return; + if(uiNewPanel(curarea, block, "Fields and Defection", "Physics", 0, 0, 318, 204)==0) return; /* should become button, option? */ if(ob->pd==NULL) { ob->pd= MEM_callocN(sizeof(PartDeflect), "PartDeflect"); /* and if needed, init here */ - ob->pd->pdef_sbdamp = 0.1; - ob->pd->pdef_sbift = 0.2; - ob->pd->pdef_sboft = 0.02; + ob->pd->pdef_sbdamp = 0.1f; + ob->pd->pdef_sbift = 0.2f; + ob->pd->pdef_sboft = 0.02f; } if(ob->pd) { PartDeflect *pd= ob->pd; + char *menustr= MEM_mallocN(256, "temp string"); + char *tipstr="Choose field type"; uiDefBut(block, LABEL, 0, "Fields", 10,180,140,20, NULL, 0.0, 0, 0, 0, ""); - uiBlockBeginAlign(block); - uiDefButS(block, ROW, B_FIELD_DEP, "None", 10,160,50,20, &pd->forcefield, 1.0, 0, 0, 0, "No force"); - uiDefButS(block, ROW, B_FIELD_DEP, "Force field", 60,160,90,20, &pd->forcefield, 1.0, PFIELD_FORCE, 0, 0, "Object center attracts or repels particles"); - uiDefButS(block, ROW, B_FIELD_DEP, "Wind", 10,140,50,20, &pd->forcefield, 1.0, PFIELD_WIND, 0, 0, "Constant force applied in direction of Object Z axis"); - uiDefButS(block, ROW, B_FIELD_DEP, "Vortex field", 60,140,90,20, &pd->forcefield, 1.0, PFIELD_VORTEX, 0, 0, "Particles swirl around Z-axis of the object"); - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_FIELD_CHANGE, "Strength: ", 10,110,140,20, &pd->f_strength, -1000, 1000, 10, 0, "Strength of force field"); - uiDefButF(block, NUM, B_FIELD_CHANGE, "Fall-off: ", 10,90,140,20, &pd->f_power, 0, 10, 100, 0, "Falloff power (real gravitational fallof = 2)"); + /* setup menu button */ + sprintf(menustr, "Field Type%%t|None %%x0|Spherical %%x%d|Wind %%x%d|Vortex %%x%d|Curve Guide %%x%d", + PFIELD_FORCE, PFIELD_WIND, PFIELD_VORTEX, PFIELD_GUIDE); - uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, PFIELD_USEMAX, B_FIELD_CHANGE, "Use MaxDist", 10,60,140,20, &pd->flag, 0.0, 0, 0, 0, "Use a maximum distance for the field to work"); - uiDefButF(block, NUM, B_FIELD_CHANGE, "MaxDist: ", 10,40,140,20, &pd->maxdist, 0, 1000.0, 100, 0, "Maximum distance for the field to work"); - uiBlockEndAlign(block); - -// if(modifiers_isSoftbodyEnabled(ob)) { - if(0) { - uiDefBut(block, LABEL, 0, "Object is Soft Body,", 160,160,150,20, NULL, 0.0, 0, 0, 0, ""); - uiDefBut(block, LABEL, 0, "No Deflection possible", 160,140,150,20, NULL, 0.0, 0, 0, 0, ""); - pd->deflect= 0; - } - else { - uiDefBut(block, LABEL, 0, "Deflection", 160,180,140,20, NULL, 0.0, 0, 0, 0, ""); + if(pd->forcefield==PFIELD_FORCE) tipstr= "Object center attracts or repels particles"; + else if(pd->forcefield==PFIELD_WIND) tipstr= "Constant force applied in direction of Object Z axis"; + else if(pd->forcefield==PFIELD_VORTEX) tipstr= "Particles swirl around Z-axis of the Object"; + else if(pd->forcefield==PFIELD_GUIDE) tipstr= "Use a Curve Path to guide particles"; + + uiDefButS(block, MENU, B_FIELD_DEP, menustr, 10,160,140,20, &pd->forcefield, 0.0, 0.0, 0, 0, tipstr); + MEM_freeN(menustr); + + if(pd->forcefield) { + uiBlockBeginAlign(block); + if(pd->forcefield == PFIELD_GUIDE) { + uiDefButF(block, NUM, B_FIELD_CHANGE, "MinDist: ", 10,120,140,20, &pd->f_strength, 0.0, 1000.0, 10, 0, "The distance from which particles are affected fully."); + uiDefButF(block, NUM, B_FIELD_CHANGE, "Fall-off: ", 10,100,140,20, &pd->f_power, 0.0, 10.0, 10, 0, "Falloff factor, between mindist and maxdist"); + } + else { + uiDefButF(block, NUM, B_FIELD_CHANGE, "Strength: ", 10,110,140,20, &pd->f_strength, -1000, 1000, 10, 0, "Strength of force field"); + uiDefButF(block, NUM, B_FIELD_CHANGE, "Fall-off: ", 10,90,140,20, &pd->f_power, 0, 10, 10, 0, "Falloff power (real gravitational fallof = 2)"); + } - /* only meshes collide now */ - if(ob->type==OB_MESH) { - uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",160,160,150,20, &pd->deflect, 0, 0, 0, 0, "Deflects particles based on collision"); + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, PFIELD_USEMAX, B_FIELD_CHANGE, "Use MaxDist", 10,60,140,20, &pd->flag, 0.0, 0, 0, 0, "Use a maximum distance for the field to work"); + uiDefButF(block, NUM, B_FIELD_CHANGE, "MaxDist: ", 10,40,140,20, &pd->maxdist, 0, 1000.0, 10, 0, "Maximum distance for the field to work"); + uiBlockEndAlign(block); + } + + uiDefBut(block, LABEL, 0, "Deflection", 160,180,140,20, NULL, 0.0, 0, 0, 0, ""); + + /* only meshes collide now */ + if(ob->type==OB_MESH) { + uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",160,160,150,20, &pd->deflect, 0, 0, 0, 0, "Deflects particles based on collision"); + if(pd->deflect) { uiDefBut(block, LABEL, 0, "Particles", 160,140,150,20, NULL, 0.0, 0, 0, 0, ""); uiBlockBeginAlign(block); @@ -1699,12 +1750,8 @@ static void object_panel_fields(Object *ob) uiDefButF(block, NUM, B_DIFF, "Damping:", 160,40,150,20, &pd->pdef_sbdamp, 0.0, 1.0, 10, 0, "Amount of damping during soft body collision"); uiDefButF(block, NUM, B_DIFF, "Inner:", 160,20,150,20, &pd->pdef_sbift, 0.001, 1.0, 10, 0, "Inner face thickness"); uiDefButF(block, NUM, B_DIFF, "Outer:", 160, 0,150,20, &pd->pdef_sboft, 0.001, 1.0, 10, 0, "Outer face thickness"); - uiBlockBeginAlign(block); -/* seems to be working fine .. so we do use modifier stack by default .. code here rests for debugging - uiDefButBitS(block, TOG, PDEFLE_DEFORM , 0,"UMS or CRASH", 0,0,150,20, &pd->flag, 0, 0, 0, 0, "Let collision object move with armatures/lattices WARNING logical circles will CRASH"); -*/ - } - } + } + } } } @@ -1741,7 +1788,7 @@ static void object_softbodies(Object *ob) uiBlock *block; block= uiNewBlock(&curarea->uiblocks, "object_softbodies", UI_EMBOSS, UI_HELV, curarea->win); - if(uiNewPanel(curarea, block, "Soft Body", "Physics", 740, 0, 318, 204)==0) return; + if(uiNewPanel(curarea, block, "Soft Body", "Physics", 640, 0, 318, 204)==0) return; /* do not allow to combine with force fields */ /* if(ob->pd && ob->pd->deflect) { */ @@ -1842,115 +1889,145 @@ static void object_softbodies(Object *ob) } +static void object_panel_particles_motion(Object *ob) +{ + uiBlock *block; + PartEff *paf= give_parteff(ob); + + if (paf==NULL) return; + + block= uiNewBlock(&curarea->uiblocks, "object_panel_particles_motion", UI_EMBOSS, UI_HELV, curarea->win); + uiNewPanelTabbed("Particles ", "Physics"); + if(uiNewPanel(curarea, block, "Particle Motion", "Physics", 320, 0, 318, 204)==0) return; + + /* top row */ + uiBlockBeginAlign(block); + uiDefButI(block, NUM, B_CALCEFFECT, "Keys:", 0,180,75,20, &paf->totkey, 1.0, 100.0, 0, 0, "Specify the number of key positions"); + uiDefButBitS(block, TOG, PAF_BSPLINE, B_CALCEFFECT, "Bspline", 75,180,75,20, &paf->flag, 0, 0, 0, 0, "Use B spline formula for particle interpolation"); + uiDefButI(block, NUM, B_CALCEFFECT, "Seed:", 150,180,75,20, &paf->seed, 0.0, 255.0, 0, 0, "Set an offset in the random table"); + uiDefButF(block, NUM, B_CALCEFFECT, "RLife:", 225,180,85,20, &paf->randlife, 0.0, 2.0, 10, 1, "Give the particlelife a random variation"); + uiBlockEndAlign(block); + + /* left collumn */ + uiDefBut(block, LABEL, 0, "Velocity:", 0,150,150,20, NULL, 0.0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiBlockSetCol(block, TH_BUT_SETTING2); + uiDefButF(block, NUM, B_CALCEFFECT, "Normal:", 0,130,150,20, &paf->normfac, -2.0, 2.0, 1, 3, "Let the mesh give the particle a starting speed"); + uiDefButF(block, NUM, B_CALCEFFECT, "Object:", 0,110,150,20, &paf->obfac, -1.0, 1.0, 1, 3, "Let the object give the particle a starting speed"); + uiDefButF(block, NUM, B_CALCEFFECT, "Random:", 0,90,150,20, &paf->randfac, 0.0, 2.0, 1, 3, "Give the startingspeed a random variation"); + uiDefButF(block, NUM, B_CALCEFFECT, "Texture:", 0,70,150,20, &paf->texfac, 0.0, 2.0, 1, 3, "Let the texture give the particle a starting speed"); + uiDefButF(block, NUM, B_CALCEFFECT, "Damping:", 0,50,150,20, &paf->damp, 0.0, 1.0, 1, 3, "Specify the damping factor"); + uiBlockEndAlign(block); + uiBlockSetCol(block, TH_AUTO); + + uiDefBut(block, LABEL, 0, "Texture Emission", 0,30,150,20, NULL, 0.0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG3, PAF_TEXTIME, B_CALCEFFECT, "TexEmit", 0,10,75,20, &(paf->flag2), 0, 0, 0, 0, "Use a texture to define emission of particles"); + uiDefButS(block, NUM, B_CALCEFFECT, "Tex:", 75,10,75,20, &paf->timetex, 1.0, 8.0, 0, 0, "Specify texture used for the texture emission"); + + /* right collumn */ + uiBlockBeginAlign(block); + uiDefBut(block, LABEL, 0, "Force:", 160,130,75,20, NULL, 0.0, 0, 0, 0, ""); + uiDefButF(block, NUM, B_CALCEFFECT, "X:", 235,130,75,20, paf->force, -1.0, 1.0, 1, 2, "Specify the X axis of a continues force"); + uiDefButF(block, NUM, B_CALCEFFECT, "Y:", 160,110,75,20, paf->force+1,-1.0, 1.0, 1, 2, "Specify the Y axis of a continues force"); + uiDefButF(block, NUM, B_CALCEFFECT, "Z:", 235,110,75,20, paf->force+2, -1.0, 1.0, 1, 2, "Specify the Z axis of a continues force"); + + uiBlockBeginAlign(block); + uiDefButS(block, NUM, B_CALCEFFECT, "Tex:", 160,80,75,20, &paf->speedtex, 1.0, 10.0, 0, 2, "Specify the texture used for force"); + uiDefButF(block, NUM, B_CALCEFFECT, "X:", 235,80,75,20, paf->defvec, -1.0, 1.0, 1, 2, "Specify the X axis of a force, determined by the texture"); + uiDefButF(block, NUM, B_CALCEFFECT, "Y:", 160,60,75,20, paf->defvec+1,-1.0, 1.0, 1, 2, "Specify the Y axis of a force, determined by the texture"); + uiDefButF(block, NUM, B_CALCEFFECT, "Z:", 235,60,75,20, paf->defvec+2, -1.0, 1.0, 1, 2, "Specify the Z axis of a force, determined by the texture"); + + uiBlockBeginAlign(block); + uiDefButS(block, ROW, B_CALCEFFECT, "Int", 160,30,50,20, &paf->texmap, 14.0, 0.0, 0, 0, "Use texture intensity as a factor for texture force"); + uiDefButS(block, ROW, B_CALCEFFECT, "RGB", 210,30,50,20, &paf->texmap, 14.0, 1.0, 0, 0, "Use RGB values as a factor for particle speed vector"); + uiDefButS(block, ROW, B_CALCEFFECT, "Grad", 260,30,50,20, &paf->texmap, 14.0, 2.0, 0, 0, "Use texture gradient as a factor for particle speed vector"); + + uiDefButF(block, NUM, B_CALCEFFECT, "Nabla:", 160,10,150,20, &paf->nabla, 0.0001f, 1.0, 1, 0, "Specify the dimension of the area for gradient calculation"); + +} + + static void object_panel_particles(Object *ob) { - Effect *eff; uiBlock *block; - int a; - short x, y; + uiBut *but; + PartEff *paf= give_parteff(ob); block= uiNewBlock(&curarea->uiblocks, "object_panel_particles", UI_EMBOSS, UI_HELV, curarea->win); - if(uiNewPanel(curarea, block, "Particles", "Physics", 0, 0, 418, 204)==0) return; + if(uiNewPanel(curarea, block, "Particles ", "Physics", 320, 0, 318, 204)==0) return; - /* EFFECTS */ - if (ob->type == OB_MESH) { uiBlockBeginAlign(block); - uiDefBut(block, BUT, B_NEWEFFECT, "NEW", 550,187,124,27, 0, 0, 0, 0, 0, "Create a new Particle effect"); - uiDefBut(block, BUT, B_DELEFFECT, "Delete", 676,187,62,27, 0, 0, 0, 0, 0, "Delete the effect"); - uiBlockEndAlign(block); - } - - /* select effs */ - eff= ob->effect.first; - a= 0; - while(eff) { - - x= 15 * a + 550; - y= 172; // - 12*( abs(a/10) ) ; - uiDefButBitS(block, TOG, SELECT, B_SELEFFECT+a, "", x, y, 15, 12, &eff->flag, 0, 0, 0, 0, ""); - - a++; - if(a==MAX_EFFECT) break; - eff= eff->next; + if(paf==NULL) + uiDefBut(block, BUT, B_NEWEFFECT, "NEW", 0,180,75,20, 0, 0, 0, 0, 0, "Create a new Particle effect"); + else + uiDefBut(block, BUT, B_DELEFFECT, "Delete", 0,180,75,20, 0, 0, 0, 0, 0, "Delete the effect"); } + else uiDefBut(block, LABEL, 0, "Only Mesh Objects can generate particles", 10,180,300,20, NULL, 0.0, 0, 0, 0, ""); - eff= ob->effect.first; - while(eff) { - if(eff->flag & SELECT) break; - eff= eff->next; - } - if(eff) { - if(eff->type==EFF_PARTICLE) { - PartEff *paf; - - paf= (PartEff *)eff; - - uiDefBut(block, BUT, B_RECALCAL, "RecalcAll", 741,187,67,27, 0, 0, 0, 0, 0, "Update the particle system"); - uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, PAF_STATIC, B_EFFECT_DEP, "Static", 825,187,67,27, &paf->flag, 0, 0, 0, 0, "Make static particles (deform only works with SubSurf)"); - if(paf->flag & PAF_STATIC) { - uiDefButBitS(block, TOG, PAF_ANIMATED, B_DIFF, "Animated",895,187,107,27, &paf->flag, 0, 0, 0, 0, "Static particles are recalculated each rendered frame"); - } - uiBlockBeginAlign(block); - uiDefButI(block, NUM, B_CALCEFFECT, "Tot:", 550,146,91,20, &paf->totpart, 1.0, 100000.0, 0, 0, "Set the total number of particles"); - if(paf->flag & PAF_STATIC) { - uiDefButS(block, NUM, REDRAWVIEW3D, "Step:", 644,146,84+97,20, &paf->staticstep, 1.0, 100.0, 10, 0, "For static duplicators, the Step value skips particles"); - } - else { - uiDefButF(block, NUM, B_CALCEFFECT, "Sta:", 644,146,84,20, &paf->sta, -250.0, MAXFRAMEF, 100, 0, "Specify the startframe"); - uiDefButF(block, NUM, B_CALCEFFECT, "End:", 731,146,97,20, &paf->end, 1.0, MAXFRAMEF, 100, 0, "Specify the endframe"); - } - uiDefButF(block, NUM, B_CALCEFFECT, "Life:", 831,146,88,20, &paf->lifetime, 1.0, MAXFRAMEF, 100, 0, "Specify the life span of the particles"); - uiDefButI(block, NUM, B_CALCEFFECT, "Keys:", 922,146,80,20, &paf->totkey, 1.0, 100.0, 0, 0, "Specify the number of key positions"); - - uiDefButS(block, NUM, B_REDR, "CurMul:", 550,124,91,20, &paf->curmult, 0.0, 3.0, 0, 0, "Multiply the particles"); - uiDefButS(block, NUM, B_CALCEFFECT, "Mat:", 644,124,84,20, paf->mat+paf->curmult, 1.0, 8.0, 0, 0, "Specify the material used for the particles"); - uiDefButF(block, NUM, B_CALCEFFECT, "Mult:", 730,124,98,20, paf->mult+paf->curmult, 0.0, 1.0, 10, 0, "Probability \"dying\" particle spawns a new one."); - uiDefButF(block, NUM, B_CALCEFFECT, "Life:", 831,124,89,20, paf->life+paf->curmult, 1.0, 600.0, 100, 0, "Specify the lifespan of the next generation particles"); - uiDefButS(block, NUM, B_CALCEFFECT, "Child:", 922,124,80,20, paf->child+paf->curmult, 1.0, 600.0, 100, 0, "Specify the number of children of a particle that multiply itself"); - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_CALCEFFECT, "Randlife:", 550,96,96,20, &paf->randlife, 0.0, 2.0, 10, 0, "Give the particlelife a random variation"); - uiDefButI(block, NUM, B_CALCEFFECT, "Seed:", 652,96,80,20, &paf->seed, 0.0, 255.0, 0, 0, "Set an offset in the random table"); - - uiDefButBitS(block, TOG, PAF_FACE, B_CALCEFFECT, "Face", 735,96,46,20, &paf->flag, 0, 0, 0, 0, "Emit particles also from faces"); - uiDefButBitS(block, TOG, PAF_BSPLINE, B_CALCEFFECT, "Bspline", 782,96,54,20, &paf->flag, 0, 0, 0, 0, "Use B spline formula for particle interpolation"); - uiDefButS(block, TOG, REDRAWVIEW3D, "Vect", 837,96,45,20, &paf->stype, 0, 0, 0, 0, "Give the particles a rotation direction"); - uiDefButF(block, NUM, B_DIFF, "VectSize", 885,96,116,20, &paf->vectsize, 0.0, 1.0, 10, 0, "Set the speed for Vect"); - - uiBlockBeginAlign(block); - uiBlockSetCol(block, TH_BUT_SETTING2); - uiDefButF(block, NUM, B_CALCEFFECT, "Norm:", 550,67,96,20, &paf->normfac, -2.0, 2.0, 10, 0, "Let the mesh give the particle a starting speed"); - uiDefButF(block, NUM, B_CALCEFFECT, "Ob:", 649,67,86,20, &paf->obfac, -1.0, 1.0, 10, 0, "Let the object give the particle a starting speed"); - uiDefButF(block, NUM, B_CALCEFFECT, "Rand:", 738,67,86,20, &paf->randfac, 0.0, 2.0, 10, 0, "Give the startingspeed a random variation"); - uiDefButF(block, NUM, B_CALCEFFECT, "Tex:", 826,67,85,20, &paf->texfac, 0.0, 2.0, 10, 0, "Let the texture give the particle a starting speed"); - uiDefButF(block, NUM, B_CALCEFFECT, "Damp:", 913,67,89,20, &paf->damp, 0.0, 1.0, 10, 0, "Specify the damping factor"); - uiBlockSetCol(block, TH_AUTO); - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_CALCEFFECT, "X:", 550,31,72,20, paf->force, -1.0, 1.0, 1, 0, "Specify the X axis of a continues force"); - uiDefButF(block, NUM, B_CALCEFFECT, "Y:", 624,31,78,20, paf->force+1,-1.0, 1.0, 1, 0, "Specify the Y axis of a continues force"); - uiDefBut(block, LABEL, 0, "Force:", 550,9,72,20, NULL, 1.0, 0, 0, 0, ""); - uiDefButF(block, NUM, B_CALCEFFECT, "Z:", 623,9,79,20, paf->force+2, -1.0, 1.0, 1, 0, "Specify the Z axis of a continues force"); - - uiBlockBeginAlign(block); - uiDefButF(block, NUM, B_CALCEFFECT, "X:", 722,31,74,20, paf->defvec, -1.0, 1.0, 1, 0, "Specify the X axis of a force, determined by the texture"); - uiDefButF(block, NUM, B_CALCEFFECT, "Y:", 798,31,74,20, paf->defvec+1,-1.0, 1.0, 1, 0, "Specify the Y axis of a force, determined by the texture"); - uiDefBut(block, LABEL, 0, "Texture:", 722,9,74,20, NULL, 1.0, 0, 0, 0, ""); - uiDefButF(block, NUM, B_CALCEFFECT, "Z:", 797,9,75,20, paf->defvec+2, -1.0, 1.0, 1, 0, "Specify the Z axis of a force, determined by the texture"); - uiBlockEndAlign(block); - - uiDefButS(block, ROW, B_CALCEFFECT, "Int", 875,9,32,43, &paf->texmap, 14.0, 0.0, 0, 0, "Use texture intensity as a factor for texture force"); - - uiBlockBeginAlign(block); - uiDefButS(block, ROW, B_CALCEFFECT, "RGB", 911,31,45,20, &paf->texmap, 14.0, 1.0, 0, 0, "Use RGB values as a factor for particle speed vector"); - uiDefButS(block, ROW, B_CALCEFFECT, "Grad", 958,31,44,20, &paf->texmap, 14.0, 2.0, 0, 0, "Use texture gradient as a factor for particle speed vector"); - uiDefButF(block, NUM, B_CALCEFFECT, "Nabla:", 911,9,91,20, &paf->nabla, 0.0001f, 1.0, 1, 0, "Specify the dimension of the area for gradient calculation"); - - } + if(paf==NULL) return; + + uiDefBut(block, BUT, B_RECALCAL, "RecalcAll", 75,180,75,20, 0, 0, 0, 0, 0, "Update all particle systems"); + uiBlockEndAlign(block); + + uiDefBut(block, LABEL, 0, "Emit:", 0,150,75,20, NULL, 0.0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButI(block, NUM, B_CALCEFFECT, "Num:", 0,130,150,20, &paf->totpart, 1.0, 100000.0, 0, 0, "The total number of particles"); + if(paf->flag & PAF_STATIC) { + uiDefButS(block, NUM, REDRAWVIEW3D, "Step:", 0,110,150,20, &paf->staticstep, 1.0, 100.0, 10, 0, "For static duplicators, the Step value skips particles"); } + else { + uiDefButF(block, NUM, B_CALCEFFECT, "Sta:", 0,110,75,20, &paf->sta, -250.0, MAXFRAMEF, 100, 1, "Frame # to start emitting particles"); + uiDefButF(block, NUM, B_CALCEFFECT, "End:", 75,110,75,20, &paf->end, 1.0, MAXFRAMEF, 100, 1, "Frame # to stop emitting particles"); + } + uiDefButF(block, NUM, B_CALCEFFECT, "Life:", 0,90,75,20, &paf->lifetime, 1.0, MAXFRAMEF, 100, 1, "Specify the life span of the particles"); + uiDefButS(block, NUM, B_CALCEFFECT, "Disp:", 75,90,75,20, &paf->disp, 1.0, 100.0, 10, 0, "Percentage of particles to calculate for 3d view"); + uiBlockEndAlign(block); + + uiDefBut(block, LABEL, 0, "From:", 0,70,75,20, NULL, 0.0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButBitS(block, TOGN, PAF_OFACE, B_CALCEFFECT, "Verts", 0,50,75,20, &paf->flag, 0, 0, 0, 0, "Emit particles from vertices"); + uiDefButBitS(block, TOG, PAF_FACE, B_CALCEFFECT, "Faces", 75,50,75,20, &paf->flag, 0, 0, 0, 0, "Emit particles from faces"); + if(paf->flag & PAF_FACE) { + uiDefButBitS(block, TOG, PAF_TRAND, B_CALCEFFECT, "Rand", 0,30,50,20, &paf->flag, 0, 0, 0, 0, "Use true random distribution from faces"); + uiDefButBitS(block, TOG, PAF_EDISTR, B_CALCEFFECT, "Even", 50,30,50,20, &paf->flag, 0, 0, 0, 0, "Use even distribution from faces based on face areas"); + uiDefButS(block, NUM, B_CALCEFFECT, "P/F:", 100,30,50,20, &paf->userjit, 0.0, 200.0, 1, 0, "Jitter table distribution: maximum particles per face (0=uses default)"); + } + else uiBlockEndAlign(block); /* vgroup button no align */ + + but=uiDefBut(block, TEX, B_PAF_SET_VG, "VGroup:", 0,10,150,20, paf->vgroupname, 0, 31, 0, 0, "Name of vertex group to use"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)OBACT); + uiBlockEndAlign(block); + + /* right collumn */ + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, PAF_STATIC, B_EFFECT_DEP, "Static", 160,180,75,20, &paf->flag, 0, 0, 0, 0, "Make static particles (deform only works with SubSurf)"); + if(paf->flag & PAF_STATIC) { + uiDefButBitS(block, TOG, PAF_ANIMATED, B_DIFF, "Animated", 235,180,75,20, &paf->flag, 0, 0, 0, 0, "Static particles are recalculated each rendered frame"); + } + uiBlockEndAlign(block); + + uiDefBut(block, LABEL, 0, "Display:", 160,150,75,20, NULL, 0.0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButS(block, NUM, B_CALCEFFECT, "Material:", 160,130,150,20, &paf->omat, 1.0, 16.0, 0, 0, "Specify material used for the particles"); + uiDefButS(block, TOG|BIT|7, B_REDR, "Mesh", 160,110,50,20, &paf->flag, 0, 0, 0, 0, "Render emitter Mesh also"); + uiDefButBitS(block, TOG, PAF_UNBORN, B_DIFF, "Unborn",210,110,50,20, &paf->flag, 0, 0, 0, 0, "Make particles appear before they are emitted"); + uiDefButBitS(block, TOG, PAF_DIED, B_DIFF, "Died", 260,110,50,20, &paf->flag, 0, 0, 0, 0, "Make particles appear after they have died"); + uiDefButS(block, TOG, REDRAWVIEW3D, "Vect", 160,90,75,20, &paf->stype, 0, 0, 0, 0, "Give the particles a direction and rotation"); + uiDefButF(block, NUM, B_DIFF, "Size:", 235,90,75,20, &paf->vectsize, 0.0, 1.0, 10, 1, "The amount the Vect option influences halo size"); + uiBlockEndAlign(block); + + uiDefBut(block, LABEL, 0, "Children:", 160,70,75,20, NULL, 0.0, 0, 0, 0, ""); + uiBlockBeginAlign(block); + uiDefButS(block, NUM, B_REDR, "Generation:", 160,50,150,20, &paf->curmult, 0.0, 3.0, 0, 0, "Current generation of particles"); + uiDefButS(block, NUM, B_CALCEFFECT, "Num:", 160,30,75,20, paf->child+paf->curmult, 1.0, 600.0, 100, 0, "Specify the number of generations of particles that can multiply itself"); + uiDefButF(block, NUM, B_CALCEFFECT, "Prob:", 235,30,75,20, paf->mult+paf->curmult, 0.0, 1.0, 10, 1, "Probability \"dying\" particle spawns a new one."); + uiDefButF(block, NUM, B_CALCEFFECT, "Life:", 160,10,75,20, paf->life+paf->curmult, 1.0, 600.0, 100, 1, "Specify the lifespan of the next generation particles"); + uiDefButS(block, NUM, B_CALCEFFECT, "Mat:", 235,10,75,20, paf->mat+paf->curmult, 1.0, 8.0, 0, 0, "Specify the material used for the particles"); + uiBlockEndAlign(block); + } /* NT - Panel for fluidsim settings */ @@ -1963,6 +2040,7 @@ static void object_panel_fluidsim(Object *ob) const int objHeight = 20; block= uiNewBlock(&curarea->uiblocks, "object_fluidsim", UI_EMBOSS, UI_HELV, curarea->win); + uiNewPanelTabbed("Soft Body", "Physics"); if(uiNewPanel(curarea, block, "Fluid Simulation", "Physics", 1060, 0, 318, 204)==0) return; uiDefButBitS(block, TOG, OB_FLUIDSIM_ENABLE, REDRAWBUTSOBJECT, "Enable", 0,yline, 75,objHeight, @@ -2130,8 +2208,9 @@ void physics_panels() ob= OBACT; if(ob) { if(ob->id.lib) uiSetButLock(1, "Can't edit library data"); - object_panel_particles(ob); object_panel_fields(ob); + object_panel_particles(ob); + object_panel_particles_motion(ob); object_softbodies(ob); object_panel_fluidsim(ob); } diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c index 9323ac6ea2e..60383de8b14 100644 --- a/source/blender/src/drawobject.c +++ b/source/blender/src/drawobject.c @@ -87,6 +87,7 @@ #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_object.h" +#include "BKE_anim.h" //for the where_on_path function #include "BIF_gl.h" #include "BIF_glutil.h" @@ -2390,10 +2391,10 @@ static void draw_static_particle_system(Object *ob, PartEff *paf) int a; pa= paf->keys; - if(pa==0) { + if(pa==NULL) { build_particle_system(ob); pa= paf->keys; - if(pa==0) return; + if(pa==NULL) return; } glPointSize(1.0); @@ -2978,6 +2979,13 @@ static void draw_forcefield(Object *ob) PartDeflect *pd= ob->pd; float imat[4][4], tmat[4][4]; float vec[3]= {0.0, 0.0, 0.0}; + int curcol; + + if(ob!=G.obedit && (ob->flag & SELECT)) { + if(ob==OBACT) curcol= TH_ACTIVE; + else curcol= TH_SELECT; + } + else curcol= TH_WIRE; /* calculus here, is reused in PFIELD_FORCE */ mygetmatrix(tmat); @@ -2985,17 +2993,11 @@ static void draw_forcefield(Object *ob) // Normalise(imat[0]); // we don't do this because field doesnt scale either... apart from wind! // Normalise(imat[1]); - if(pd->flag & PFIELD_USEMAX) { - setlinestyle(3); - BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.5); - drawcircball(GL_LINE_LOOP, vec, pd->maxdist, imat); - setlinestyle(0); - } if (pd->forcefield == PFIELD_WIND) { float force_val; Mat4One(tmat); - BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.5); + BIF_ThemeColorBlend(curcol, TH_BACK, 0.5); if (has_ipo_code(ob->ipo, OB_PD_FSTR)) force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, G.scene->r.cfra); @@ -3019,11 +3021,11 @@ static void draw_forcefield(Object *ob) else ffall_val = pd->f_power; - BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.5); + BIF_ThemeColorBlend(curcol, TH_BACK, 0.5); drawcircball(GL_LINE_LOOP, vec, 1.0, imat); - BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.9 - 0.4 / pow(1.5, (double)ffall_val)); + BIF_ThemeColorBlend(curcol, TH_BACK, 0.9 - 0.4 / pow(1.5, (double)ffall_val)); drawcircball(GL_LINE_LOOP, vec, 1.5, imat); - BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.9 - 0.4 / pow(2.0, (double)ffall_val)); + BIF_ThemeColorBlend(curcol, TH_BACK, 0.9 - 0.4 / pow(2.0, (double)ffall_val)); drawcircball(GL_LINE_LOOP, vec, 2.0, imat); } else if (pd->forcefield == PFIELD_VORTEX) { @@ -3040,7 +3042,7 @@ static void draw_forcefield(Object *ob) else force_val = pd->f_strength; - BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7); + BIF_ThemeColorBlend(curcol, TH_BACK, 0.7); if (force_val < 0) { drawspiral(vec, 1.0, imat, 1); drawspiral(vec, 1.0, imat, 16); @@ -3050,7 +3052,39 @@ static void draw_forcefield(Object *ob) drawspiral(vec, 1.0, imat, -16); } } + else if (pd->forcefield == PFIELD_GUIDE && ob->type==OB_CURVE) { + Curve *cu= ob->data; + if((cu->flag & CU_PATH) && cu->path && cu->path->data) { + float mindist, guidevec1[4], guidevec2[3]; + + if (has_ipo_code(ob->ipo, OB_PD_FSTR)) + mindist = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, G.scene->r.cfra); + else + mindist = pd->f_strength; + + /*path end*/ + setlinestyle(3); + where_on_path(ob, 1.0f, guidevec1, guidevec2); + BIF_ThemeColorBlend(curcol, TH_BACK, 0.5); + drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat); + + /*path beginning*/ + setlinestyle(0); + where_on_path(ob, 0.0f, guidevec1, guidevec2); + BIF_ThemeColorBlend(curcol, TH_BACK, 0.5); + drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat); + + VECCOPY(vec, guidevec1); /* max center */ + } + } + /* as last, guide curve alters it */ + if(pd->flag & PFIELD_USEMAX) { + setlinestyle(3); + BIF_ThemeColorBlend(curcol, TH_BACK, 0.5); + drawcircball(GL_LINE_LOOP, vec, pd->maxdist, imat); + setlinestyle(0); + } } static void draw_box(float vec[8][3]) @@ -3480,7 +3514,7 @@ void draw_object(Base *base) PartEff *paf = give_parteff(ob); if(paf) { - if(col) cpack(0xFFFFFF); /* for visibility */ + if(col || (ob->flag & SELECT)) cpack(0xFFFFFF); /* for visibility, also while wpaint */ if(paf->flag & PAF_STATIC) draw_static_particle_system(ob, paf); else if((G.f & G_PICKSEL) == 0) draw_particle_system(ob, paf); // selection errors happen to easy if(col) cpack(col); diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index 7a8375ba0cc..5fdd2aa3980 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -1539,7 +1539,8 @@ void exit_editmode(int freedata) /* freedata==0 at render, 1= freedata, 2= do un sbObjectToSoftbody(ob); } - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + /* also flush ob recalc, doesn't take much overhead, but used for particles */ + DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA); if(freedata) { setcursor_space(SPACE_VIEW3D, CURSOR_STD);