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! :)
This commit is contained in:
Ton Roosendaal 2005-11-10 16:01:56 +00:00
parent 0093857b4f
commit f8845d5d11
15 changed files with 1375 additions and 741 deletions

@ -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);

@ -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,8 +489,10 @@ void particle_duplilist(Scene *sce, Object *par, PartEff *paf)
}
else { // non static particles
if(ctime > pa->time) {
if(ctime < pa->time+pa->lifetime) {
if((paf->flag & PAF_UNBORN)==0 && ctime < pa->time) continue;
if((paf->flag & PAF_DIED)==0 && ctime > pa->time+pa->lifetime) continue;
//if(ctime < pa->time+pa->lifetime) {
newob= new_dupli_object(&duplilist, ob, par);
/* to give ipos in object correct offset */
@ -510,8 +513,6 @@ void particle_duplilist(Scene *sce, Object *par, PartEff *paf)
VECCOPY(newob->obmat[3], vec);
}
}
}
}
break;
}
ob= ob->parent;

@ -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) {

File diff suppressed because it is too large Load Diff

@ -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);
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;
}

@ -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) {

@ -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

@ -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

@ -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;

@ -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

@ -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,9 +839,20 @@ 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) {
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);
@ -896,8 +907,6 @@ static void render_particle_system(Object *ob, PartEff *paf)
}
}
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);

@ -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");
}

@ -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");
/* 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);
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, 100, 0, "Falloff power (real gravitational fallof = 2)");
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, 100, 0, "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);
// if(modifiers_isSoftbodyEnabled(ob)) {
if(0) {
uiDefBut(block, LABEL, 0, "Object is Soft Body,", 160,160,150,20, NULL, 0.0, 0, 0, 0, "");
uiDefBut(block, LABEL, 0, "No Deflection possible", 160,140,150,20, NULL, 0.0, 0, 0, 0, "");
pd->deflect= 0;
}
else {
uiDefBut(block, LABEL, 0, "Deflection", 160,180,140,20, NULL, 0.0, 0, 0, 0, "");
/* 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,10 +1750,6 @@ 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;
/* EFFECTS */
if(uiNewPanel(curarea, block, "Particles ", "Physics", 320, 0, 318, 204)==0) return;
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");
if(paf==NULL)
uiDefBut(block, BUT, B_NEWEFFECT, "NEW", 0,180,75,20, 0, 0, 0, 0, 0, "Create a new Particle effect");
else
uiDefBut(block, BUT, B_DELEFFECT, "Delete", 0,180,75,20, 0, 0, 0, 0, 0, "Delete the effect");
}
else uiDefBut(block, LABEL, 0, "Only Mesh Objects can generate particles", 10,180,300,20, NULL, 0.0, 0, 0, 0, "");
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);
}
/* 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;
}
eff= ob->effect.first;
while(eff) {
if(eff->flag & SELECT) break;
eff= eff->next;
}
if(eff) {
if(eff->type==EFF_PARTICLE) {
PartEff *paf;
paf= (PartEff *)eff;
uiDefBut(block, BUT, B_RECALCAL, "RecalcAll", 741,187,67,27, 0, 0, 0, 0, 0, "Update the particle system");
uiDefBut(block, LABEL, 0, "Emit:", 0,150,75,20, NULL, 0.0, 0, 0, 0, "");
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)");
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) {
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");
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:", 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, "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:", 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");
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);
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");
uiDefBut(block, LABEL, 0, "From:", 0,70,75,20, NULL, 0.0, 0, 0, 0, "");
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");
uiDefButBitS(block, TOGN, PAF_OFACE, B_CALCEFFECT, "Verts", 0,50,75,20, &paf->flag, 0, 0, 0, 0, "Emit particles from vertices");
uiDefButBitS(block, TOG, PAF_FACE, B_CALCEFFECT, "Faces", 75,50,75,20, &paf->flag, 0, 0, 0, 0, "Emit particles from faces");
if(paf->flag & PAF_FACE) {
uiDefButBitS(block, TOG, PAF_TRAND, B_CALCEFFECT, "Rand", 0,30,50,20, &paf->flag, 0, 0, 0, 0, "Use true random distribution from faces");
uiDefButBitS(block, TOG, PAF_EDISTR, B_CALCEFFECT, "Even", 50,30,50,20, &paf->flag, 0, 0, 0, 0, "Use even distribution from faces based on face areas");
uiDefButS(block, NUM, B_CALCEFFECT, "P/F:", 100,30,50,20, &paf->userjit, 0.0, 200.0, 1, 0, "Jitter table distribution: maximum particles per face (0=uses default)");
}
else uiBlockEndAlign(block); /* vgroup button no align */
but=uiDefBut(block, TEX, B_PAF_SET_VG, "VGroup:", 0,10,150,20, paf->vgroupname, 0, 31, 0, 0, "Name of vertex group to use");
uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)OBACT);
uiBlockEndAlign(block);
/* right collumn */
uiBlockBeginAlign(block);
uiDefButBitS(block, TOG, PAF_STATIC, B_EFFECT_DEP, "Static", 160,180,75,20, &paf->flag, 0, 0, 0, 0, "Make static particles (deform only works with SubSurf)");
if(paf->flag & PAF_STATIC) {
uiDefButBitS(block, TOG, PAF_ANIMATED, B_DIFF, "Animated", 235,180,75,20, &paf->flag, 0, 0, 0, 0, "Static particles are recalculated each rendered frame");
}
}
uiBlockEndAlign(block);
uiDefBut(block, LABEL, 0, "Display:", 160,150,75,20, NULL, 0.0, 0, 0, 0, "");
uiBlockBeginAlign(block);
uiDefButS(block, NUM, B_CALCEFFECT, "Material:", 160,130,150,20, &paf->omat, 1.0, 16.0, 0, 0, "Specify material used for the particles");
uiDefButS(block, TOG|BIT|7, B_REDR, "Mesh", 160,110,50,20, &paf->flag, 0, 0, 0, 0, "Render emitter Mesh also");
uiDefButBitS(block, TOG, PAF_UNBORN, B_DIFF, "Unborn",210,110,50,20, &paf->flag, 0, 0, 0, 0, "Make particles appear before they are emitted");
uiDefButBitS(block, TOG, PAF_DIED, B_DIFF, "Died", 260,110,50,20, &paf->flag, 0, 0, 0, 0, "Make particles appear after they have died");
uiDefButS(block, TOG, REDRAWVIEW3D, "Vect", 160,90,75,20, &paf->stype, 0, 0, 0, 0, "Give the particles a direction and rotation");
uiDefButF(block, NUM, B_DIFF, "Size:", 235,90,75,20, &paf->vectsize, 0.0, 1.0, 10, 1, "The amount the Vect option influences halo size");
uiBlockEndAlign(block);
uiDefBut(block, LABEL, 0, "Children:", 160,70,75,20, NULL, 0.0, 0, 0, 0, "");
uiBlockBeginAlign(block);
uiDefButS(block, NUM, B_REDR, "Generation:", 160,50,150,20, &paf->curmult, 0.0, 3.0, 0, 0, "Current generation of particles");
uiDefButS(block, NUM, B_CALCEFFECT, "Num:", 160,30,75,20, paf->child+paf->curmult, 1.0, 600.0, 100, 0, "Specify the number of generations of particles that can multiply itself");
uiDefButF(block, NUM, B_CALCEFFECT, "Prob:", 235,30,75,20, paf->mult+paf->curmult, 0.0, 1.0, 10, 1, "Probability \"dying\" particle spawns a new one.");
uiDefButF(block, NUM, B_CALCEFFECT, "Life:", 160,10,75,20, paf->life+paf->curmult, 1.0, 600.0, 100, 1, "Specify the lifespan of the next generation particles");
uiDefButS(block, NUM, B_CALCEFFECT, "Mat:", 235,10,75,20, paf->mat+paf->curmult, 1.0, 8.0, 0, 0, "Specify the material used for the particles");
uiBlockEndAlign(block);
}
/* NT - Panel for fluidsim settings */
@ -1963,6 +2040,7 @@ static void object_panel_fluidsim(Object *ob)
const int objHeight = 20;
block= uiNewBlock(&curarea->uiblocks, "object_fluidsim", UI_EMBOSS, UI_HELV, curarea->win);
uiNewPanelTabbed("Soft Body", "Physics");
if(uiNewPanel(curarea, block, "Fluid Simulation", "Physics", 1060, 0, 318, 204)==0) return;
uiDefButBitS(block, TOG, OB_FLUIDSIM_ENABLE, REDRAWBUTSOBJECT, "Enable", 0,yline, 75,objHeight,
@ -2130,8 +2208,9 @@ void physics_panels()
ob= OBACT;
if(ob) {
if(ob->id.lib) uiSetButLock(1, "Can't edit library data");
object_panel_particles(ob);
object_panel_fields(ob);
object_panel_particles(ob);
object_panel_particles_motion(ob);
object_softbodies(ob);
object_panel_fluidsim(ob);
}

@ -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);

@ -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);