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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTon Roosendaal <ton@blender.org>2005-11-10 19:01:56 +0300
committerTon Roosendaal <ton@blender.org>2005-11-10 19:01:56 +0300
commitf8845d5d1105044779ff9cd5dc18e9d82dfcc7f9 (patch)
treeb02aef5eb5378332914209c599c5067ee30c91b8 /source/blender
parent0093857b4ffb8c65fc9a3a62f1c5fb29ed6ec9ed (diff)
The long awaited Particle patch from Janne Karhu
http://www.blender3d.org/cms/New_Particle_options_a.721.0.html There's no doubt this patch had a lot of good ideas for features, and I want to compliment Janne again for getting it all to work even! A more careful review of the features and code did show however quite some flaws and bugs... partially because the current particle code was very much polluted already, but also because of the implementation lacked quality. However, the patch was too good to reject, so I've fixed and recoded the parts that needed it most. :) Here's a list of of most evident changes in the patch; - Guides support recoded. It was implemented as a true 'force field', checking all Curve path points for each particle to find the closest. Was just far too slow, and didn't support looping or bends well. The new implementation is fast (real time) and treats the paths as actual trajectory for the particle. - Guides didn't integrate in the physics/speed system either, was added as exception. Now it's integrated and can be combined with other velocities or forces - Use of Fields was slow code in general, made it use a Cache instead. - The "even" distribution didn't work for Jittered sample patterns. - The "even" or "vertexgroup" code in the main loops were badly constructed, giving too much cpu for a simple task. Instead of going over all faces many times, it now only does it once. Same part of the code used a lot of temporal unneeded mallocs. - Use of DerivedMesh or Mesh was confused, didn't work for Subsurfs in all cases - Support for vertex groups was slow, evaluating vertexgroups too often - When a vertexgroup failed to read, it was wrongly handled (set to zero). VertexGroup support now is with a name. - Split up the too huge build_particle() call in some parts (moving new code) - The "texture re-timing" option failed for moving Objects. The old code used the convention that particles were added with increasing time steps. Solved by creating a object Matrix Cache. Also: the texture coordinates had to be corrected to become "OrCo". - The "Disp" option only was used to draw less particles. Changed it to actually calculate fewer particles for 3D viewing, but render all still. So now it can be used to keep editing realtime. Removed; The "speed threshold" and "Tight" features were not copied over. This resembled too much to feature overkill. Needs re-evaluation. Also the "Deform" option was not added, I prefer to first check if the current particle system really works for the Modifier system. And: - Added integration for particle force fields in the dependency graph - Added TAB completion for vertexgroup names! - Made the 'wait cursor' only appear when particles take more than 0.5 sec - The particle jitter table order now is randomized too, giving much nicer emitting of particles in large faces. - Vortex field didn't correctly use speed/forces, so it didn't work for collisions. - Triangle distribution was wrong - Removed ancient bug that applied in a *very* weird way speed and forces. (location changes got the half force, speed the full...???) So much... might have forgotten some notes! :)
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_effect.h4
-rw-r--r--source/blender/blenkernel/intern/anim.c41
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c6
-rw-r--r--source/blender/blenkernel/intern/effect.c1331
-rw-r--r--source/blender/blenkernel/intern/softbody.c50
-rw-r--r--source/blender/blenloader/intern/readfile.c11
-rw-r--r--source/blender/include/BIF_butspace.h2
-rw-r--r--source/blender/include/butspace.h3
-rw-r--r--source/blender/makesdna/DNA_effect_types.h24
-rw-r--r--source/blender/makesdna/DNA_object_force.h1
-rw-r--r--source/blender/renderconverter/intern/convertBlenderScene.c122
-rw-r--r--source/blender/src/buttons_editing.c15
-rw-r--r--source/blender/src/buttons_object.c385
-rw-r--r--source/blender/src/drawobject.c62
-rw-r--r--source/blender/src/editobject.c3
15 files changed, 1347 insertions, 713 deletions
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);
-
- QuatToMat3(q2, mat);
- Mat4CpyMat4(tmat, newob->obmat);
- Mat4MulMat43(newob->obmat, tmat, mat);
- }
+ //if(ctime < pa->time+pa->lifetime) {
+ newob= new_dupli_object(&duplilist, ob, par);
- VECCOPY(newob->obmat[3], vec);
- }
+ /* 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);
+
+ 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+1<paf->totkey) p[2]= pa+1; else p[2]= pa;
if(a+2<paf->totkey) p[3]= pa+2; else p[3]= p[2];
- if(p[1]==p[2]) 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) */
+
+ /* 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) {
- /* use center of object for distance calculus */
+ /* 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];
- 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];
+ /* 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);
+ /* Now calculate the vortex 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 );
+ 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 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)));
- speed[0] -= (force_vec[0] * f_force );
- speed[1] -= (force_vec[1] * f_force );
- speed[2] -= (force_vec[2] * f_force );
-
+ 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; b<paf->totkey; 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];
-
- 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];
-
- /* 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);
+ VECCOPY(opco, opa->co);
+ VECCOPY(new_force, force);
+ VECCOPY(new_speed, opa->no);
+ VecMulf(new_speed, 1.0f/deltalife);
+ //new_speed[0] = new_speed[1] = new_speed[2] = 0.0f;
+
+ /* handle differences between static (local coords, fixed frame) and dynamic */
+ if(effectorbase) {
+ float loc_time= ((float)b)/(float)(paf->totkey-1);
- /* 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; i<tot; i++) {
+ trands[2*i]= rng_getFloat(rng);
+ trands[2*i+1]= rng_getFloat(rng);
+ }
+ rng_free(rng);
+
+ if((paf->flag & 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(paf->flag & PAF_TRAND) {
+ u= trands[2*partnr];
+ v= trands[2*partnr+1];
}
+ else {
+ /* jittered distribution gets fixed random offset */
+ if(subnr>=jitlevel) {
+ int jitrand= (subnr/jitlevel) % JIT_RAND;
+
+ subnr %= jitlevel;
+ u= jit[2*subnr] + trands[2*jitrand];
+ v= jit[2*subnr+1] + trands[2*jitrand+1];
+ if(u > 1.0f) u-= 1.0f;
+ if(v > 1.0f) v-= 1.0f;
+ }
+ else {
+ u= jit[2*subnr];
+ v= jit[2*subnr+1];
+ }
+ }
+
+ v1= (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(totface==0 || nr<totvert) {
- mvert= mvertbase + (nr % totvert);
- VECCOPY(co, mvert->co);
- VECCOPY(no, mvert->no);
+ if(mface->v4) {
+ float uv= u*v;
+ float muv= (1.0f-u)*(v);
+ float umv= (u)*(1.0f-v);
+ float mumv= (1.0f-u)*(1.0f-v);
+
+ v4= (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 {
-
- nr-= totvert;
+ /* 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]);
- if(jit==0) {
- jitlevel= nr/totface;
- if(jitlevel==0) jitlevel= 1;
- if(jitlevel>100) jitlevel= 100;
+ 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]));
+ }
+}
- jit= MEM_callocN(2+ jitlevel*2*sizeof(float), "jit");
- init_mv_jit(jit, jitlevel,seed2);
-
+
+/* 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;
+}
- curjit= nr/totface;
- curjit= curjit % jitlevel;
+/* 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;
+ }
- curface= nr % totface;
+ 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; a<totvert; a++) {
+ voweights[a]= vert_weight(me->dvert+a, paf->vertgroup-1);
+ totvweight+= voweights[a];
+ }
+
+ if(totface) {
+ /* allocate weights array for faces, note it's a malloc */
+ *fweights= foweights= MEM_mallocN(totface*sizeof(float), "paffoweights" );
+ for(a=0, mface=facelist; a<totface; a++, mface++) {
+ foweights[a] = face_weight(mface, voweights);
+ }
+ }
+ }
+
+ /* make weights for faces or for even area distribution */
+ if(totface && (paf->flag & PAF_EDISTR)) {
+ float maxfarea= 0.0f, curfarea;
- 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;
+ /* two cases for area distro, second case we already have group weights */
+ if(foweights==NULL) {
+ /* allocate weights array for faces, note it's a malloc */
+ *fweights= foweights= MEM_mallocN(totface*sizeof(float), "paffoweights" );
+
+ for(a=0, mface=facelist; a<totface; a++, mface++) {
+ if (mface->v4)
+ curfarea= AreaQ3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co, vertlist[mface->v4].co);
+ else
+ curfarea= AreaT3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co);
+ if(curfarea>maxfarea)
+ maxfarea = curfarea;
+ foweights[a]= curfarea;
+ }
}
else {
- v4= (mvertbase+(mface->v4))->co;
- n4= (mvertbase+(mface->v4))->no;
+ for(a=0, mface=facelist; a<totface; a++, mface++) {
+ if(foweights[a]!=0.0f) {
+ if (mface->v4)
+ curfarea= AreaQ3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co, vertlist[mface->v4].co);
+ else
+ curfarea= AreaT3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co);
+ if(curfarea>maxfarea)
+ maxfarea = curfarea;
+ foweights[a]*= curfarea;
+ }
+ }
+ }
+
+ /* normalize weights for max face area, calculate tot */
+ if(maxfarea!=0.0f) {
+ maxfarea= 1.0f/maxfarea;
+ for(a=0; a< totface; a++) {
+ if(foweights[a]!=0.0) {
+ foweights[a] *= maxfarea;
+ totfweight+= foweights[a];
+ }
+ }
+ }
+ }
+ else if(foweights) {
+ /* only add totfweight value */
+ for(a=0; a< totface; a++) {
+ if(foweights[a]!=0.0) {
+ totfweight+= foweights[a];
+ }
+ }
+ }
+
+ /* if weight arrays, we turn these arrays into the amount of particles */
+ if(totvert && voweights) {
+ float mult= (float)totpart/totvweight;
+
+ for(a=0; a< totvert; a++) {
+ if(voweights[a]!=0.0)
+ voweights[a] *= mult;
+ }
+ }
+
+ if(totface && foweights) {
+ float mult= (float)totpart/totfweight;
+
+ for(a=0; a< totface; a++) {
+ if(foweights[a]!=0.0)
+ foweights[a] *= mult;
}
+ }
+}
- u= jit[2*curjit];
- v= jit[2*curjit+1];
+/* for paf start to end, store all matrices for objects */
+typedef struct pMatrixCache {
+ float obmat[4][4];
+ float imat[3][3];
+} pMatrixCache;
- 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]);
+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++) {
- 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]);
+ 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;
+ 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];
+ }
- waitcursor(1);
-
- disable_speed_curve(1);
+ disable_speed_curve(1); /* check this... */
- /* generate all particles */
- if(paf->keys) MEM_freeN(paf->keys);
- paf->keys= NULL;
+ /* 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; a<PAF_MAXMULT; a++) {
if(paf->mult[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<totpart; a++, ftime+=dtime) {
+ /* we set waitcursor only when a half second expired, particles now are realtime updated */
+ if(waitcursor_set==0 && (a % 256)==255) {
+ double seconds= PIL_check_seconds_timer();
+ if(seconds - startseconds > 0.5) {
+ 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;
+ /* use weight table, we have to do faces in order to be able to use jitter table... */
+ if(foweights) {
+
+ if(foweights[curface] < 1.0f) {
+ float remainder= 0.0f;
+
+ while(remainder + foweights[curface] < 1.0f && curface<totface-1) {
+ remainder += foweights[curface];
+ curface++;
+ }
+ foweights[curface] += remainder;
+ maxw= (paf->end-paf->sta)/foweights[curface];
+ }
+
+ 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];
+ }
}
-
- b=(a%c);
- if (b==0) {
- printf("\r Particle: %d / %d ", a, totpart);
- fflush(stdout);
+ else {
+ curface= a % totface;
+ curjit= a/totface;
+ give_mesh_particle_coord(paf, vertlist, facelist+curface, a, curjit, co, no);
}
}
- /* 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);
+ /* get coordinates from vertices */
+ if(totvert) {
+ /* use weight table */
+ if(voweights) {
+
+ if(voweights[curvert] < 1.0f) {
+ float remainder= 0.0f;
+
+ while(remainder + voweights[curvert] < 1.0f && curvert<totvert-1) {
+ remainder += voweights[curvert];
+ curvert++;
}
- par= par->parent;
+ voweights[curvert] += remainder;
+ maxw= (paf->end-paf->sta)/voweights[curvert];
+ }
+
+ if(voweights[curvert]==0.0f)
+ break; /* WARN skips here out of particle generating */
+ else {
+ if(voweights[curvert] > 1.0f)
+ voweights[curvert] -= 1.0f;
+
+ /* time correction to make particles appear evenly */
+ pa->time= paf->sta + maxw*voweights[curvert];
}
- if(ma) do_mat_ipo(ma);
- Mat4CpyMat4(prevobmat, ob->obmat);
- where_is_object(ob);
- Mat4Invert(ob->imat, ob->obmat);
- Mat3CpyMat4(imat, ob->imat);
}
- }
- /* 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;
+ 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);
- }
- 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;
- }
+ /* 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();
+
/* 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; a<paf->totpart; 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((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(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);
- }
+ 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;
+ hasize= ma->hasize;
- if(ma->mode & MA_HALOPUNO) {
- xn= pa->no[0];
- yn= pa->no[1];
- zn= pa->no[2];
+ 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);
+ /* 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);
+ 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;
- }
+ 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->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 && event<B_SELEFFECT+MAX_EFFECT) {
ob= OBACT;
@@ -1642,49 +1683,59 @@ static void object_panel_fields(Object *ob)
uiBlock *block;
block= uiNewBlock(&curarea->uiblocks, "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;
+ 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)");
+ }
+
+ 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);
}
- else {
- uiDefBut(block, LABEL, 0, "Deflection", 160,180,140,20, NULL, 0.0, 0, 0, 0, "");
+
+ 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");
+ /* 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);
+ 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");
}
-
- /* 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;
+ else uiDefBut(block, LABEL, 0, "Only Mesh Objects can generate particles", 10,180,300,20, NULL, 0.0, 0, 0, 0, "");
+
+
+ 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);
- eff= ob->effect.first;
- while(eff) {
- if(eff->flag & SELECT) break;
- eff= eff->next;
+ 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 */
- 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");
+ 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);
- 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");
+ 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);