From 7a377bcb05c2634a872208680aca80cc9e9a0c11 Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Mon, 4 Apr 2005 18:09:47 +0000 Subject: - Made SoftBody work with Particle Force Fields. - Added new (Particle) Deflector; type Wind. Wind gives constant directional force. It is animatable (Ipos) and reacts to Object scaling. Also uses FallOff. Works for particles and SoftBody quick movie check; http://www.blender.org/bf/0001_0250.avi test file is in download.blender.org/demo/test/wind_soft.blend - Added MaxDist option for forcefields, to control its influence better. Is drawn as circle in 3d window. Forcefields are a bit weak still... should react to scaling, or not; in that case drawing should indicate it (done for spherical field now). --- source/blender/blenkernel/BKE_effect.h | 8 ++ source/blender/blenkernel/intern/effect.c | 122 ++++++++++++++++------------ source/blender/blenkernel/intern/softbody.c | 82 ++++++++++++++++++- source/blender/makesdna/DNA_effect_types.h | 5 -- source/blender/makesdna/DNA_object_types.h | 29 +++++-- source/blender/src/buttons_object.c | 24 ++++-- source/blender/src/drawobject.c | 47 +++++++++-- 7 files changed, 231 insertions(+), 86 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index 21663b39dd3..a5ca3708a22 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -61,5 +61,13 @@ void build_particle_system(struct Object *ob); void calc_wave_deform(struct WaveEff *wav, float ctime, float *co); int object_wave(struct Object *ob); +/* particle deflector */ +void pdDoEffector(float *opco, float *force, float *speed, float cur_time, unsigned int par_layer); +int pdDoDeflection(float opco[3], float npco[3], float opno[3], + float npno[3], float life, float force[3], int def_depth, + float cur_time, unsigned int par_layer, int *last_object, + int *last_face, int *same_face); + + #endif diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 6fe6b708f58..d811b5c0fbb 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -380,11 +380,18 @@ static int linetriangle(float p1[3], float p2[3], float v0[3], float v1[3], floa return 1; } -static void get_effector(float opco[], float force[], float speed[], float cur_time, unsigned int par_layer) +/* -------- pdDoEffector() -------- + generic force/speed system, now used for particles and softbodies + opco = global coord, as input + force = force accumulator + speed = speed accumulator + cur_time = in frames + par_layer = layer the caller is in + +*/ +void pdDoEffector(float *opco, float *force, float *speed, float cur_time, unsigned int par_layer) { /* - Particle effector field code - Modifies the force on a particle according to its relation with the effector object Different kind of effectors include: @@ -397,46 +404,75 @@ static void get_effector(float opco[], float force[], float speed[], float cur_t */ Object *ob; Base *base; + PartDeflect *pd; float vect_to_vert[3]; float force_vec[3]; float f_force, distance; - float obloc[3]; + float *obloc; float force_val, ffall_val; short cur_frame; /* Cycle through objects, get total of (1/(gravity_strength * dist^gravity_power)) */ - /* Check for min distance here? */ - base = G.scene->base.first; - while (base) { - if(base->lay & par_layer) { + /* 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; - if(ob->pd && ob->pd->forcefield == PFIELD_FORCE) { - - /* Need to set r.cfra for paths (investigate, ton) */ + 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; + + + /* 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; + } + + /* use center of object for distance calculus */ + obloc= ob->obmat[3]; + VECSUB(vect_to_vert, obloc, opco); + distance = VecLength(vect_to_vert); + + if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist) + ; /* don't do anything */ + else if(pd->forcefield == PFIELD_WIND) { + VECCOPY(force_vec, ob->obmat[2]); - /* only use center of object */ - obloc[0] = ob->obmat[3][0]; - obloc[1] = ob->obmat[3][1]; - obloc[2] = ob->obmat[3][2]; + /* wind works harder perpendicular to normal, would be nice for softbody later (ton) */ - /* 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 = ob->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 = ob->pd->f_power; + /* 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] += force_vec[0]*f_force; + force[1] += force_vec[1]*f_force; + force[2] += force_vec[2]*f_force; + + } + else if(pd->forcefield == PFIELD_FORCE) { + + /* only use center of object */ + obloc= ob->obmat[3]; /* Now calculate the gravitational force */ VECSUB(vect_to_vert, obloc, opco); - distance = Normalise(vect_to_vert); + distance = VecLength(vect_to_vert); /* Limit minimum distance to vertex so that */ /* the force is not too big */ @@ -447,33 +483,14 @@ static void get_effector(float opco[], float force[], float speed[], float cur_t force[2] += (vect_to_vert[2] * f_force ); } - else if(ob->pd && ob->pd->forcefield == PFIELD_VORTEX) { - /* Need to set r.cfra for paths (investigate, ton) */ - 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; - - /* only use center of object */ - obloc[0] = ob->obmat[3][0]; - obloc[1] = ob->obmat[3][1]; - obloc[2] = ob->obmat[3][2]; - - /* 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 = ob->pd->f_strength; + else if(pd->forcefield == PFIELD_VORTEX) { - if (has_ipo_code(ob->ipo, OB_PD_FFALL)) - ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, cur_time); - else - ffall_val = ob->pd->f_power; + /* only use center of object */ + obloc= ob->obmat[3]; /* Now calculate the vortex force */ VECSUB(vect_to_vert, obloc, opco); - - distance = Normalise(vect_to_vert); + distance = VecLength(vect_to_vert); Crossf(force_vec, ob->obmat[2], vect_to_vert); Normalise(force_vec); @@ -488,7 +505,6 @@ static void get_effector(float opco[], float force[], float speed[], float cur_t } } - base = base->next; } } @@ -513,7 +529,7 @@ static void cache_object_vertices(Object *ob) } } -static int get_deflection(float opco[3], float npco[3], float opno[3], +int pdDoDeflection(float opco[3], float npco[3], float opno[3], float npno[3], float life, float force[3], int def_depth, float cur_time, unsigned int par_layer, int *last_object, int *last_face, int *same_face) @@ -875,7 +891,7 @@ void make_particle_keys(int depth, int nr, PartEff *paf, Particle *part, float * /* Check force field */ cur_time = pa->time; - get_effector(opco, new_force, new_speed, cur_time, par_layer); + pdDoEffector(opco, new_force, new_speed, cur_time, par_layer); /* new location */ pa->co[0]= opa->co[0] + deltalife * (opa->no[0] + new_speed[0] + 0.5f*new_force[0]); @@ -910,7 +926,7 @@ void make_particle_keys(int depth, int nr, PartEff *paf, Particle *part, float * /* Bail out if we've done the calculation 10 times - this seems ok */ /* for most scenes I've tested */ while (finish_defs) { - deflected = get_deflection(opco, npco, opno, npno, life, new_force, + deflected = pdDoDeflection(opco, npco, opno, npno, life, new_force, def_count, cur_time, par_layer, &last_ob, &last_fc, &same_fc); if (deflected) { diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 240dfffa438..30e244eee93 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -69,6 +69,7 @@ variables on the UI for now #include "BLI_arithb.h" #include "BKE_displist.h" +#include "BKE_effect.h" #include "BKE_global.h" #include "BKE_object.h" #include "BKE_softbody.h" @@ -268,6 +269,22 @@ static void Vec3PlusStVec(float *v, float s, float *v1) v[2] += s*v1[2]; } +#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; + } + } + return retval; +} + static void softbody_calc_forces(Object *ob, float dtime) { @@ -276,13 +293,16 @@ static void softbody_calc_forces(Object *ob, float dtime) BodyPoint *bproot; BodySpring *bs; float iks, ks, kd, gravity, actspringlen, forcefactor, sd[3]; - int a, b; + int a, b, do_effector; /* clear forces */ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { bp->force[0]= bp->force[1]= bp->force[2]= 0.0; } + /* check! */ + do_effector= is_there_deflection(ob->lay); + gravity = sb->nodemass * sb->grav * rescale_grav_to_framerate; iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ bproot= sb->bpoint; /* need this for proper spring addressing */ @@ -334,6 +354,49 @@ static void softbody_calc_forces(Object *ob, float dtime) /* this is the place where other forces can be added yes, constraints and collision stuff should go here too (read baraff papers on that!) */ + + /* particle field & deflectors */ + if(do_effector & USES_FIELD) { + float force[3]= {0.0f, 0.0f, 0.0f}; + float speed[3]= {0.0f, 0.0f, 0.0f}; + + pdDoEffector(bp->pos, force, speed, (float)G.scene->r.cfra, ob->lay); + /* apply force */ + // VecMulf(force, rescale_grav_to_framerate); <- didn't work, made value far too low! + VECADD(bp->force, bp->force, force); + /* apply speed. note; deflector can give 'speed' only.... */ + VecMulf(speed, rescale_grav_to_framerate); + VECADD(bp->vec, bp->vec, speed); + } +#if 0 + /* copied from particles... doesn't work really! */ + if(do_effector & USES_DEFLECT) { + int deflected; + int last_ob = -1; + int last_fc = -1; + int same_fc = 0; + float last[3], lastv[3]; + int finish_defs = 1; + int def_count = 0; + + VecSubf(last, bp->pos, bp->vec); + VECCOPY(lastv, bp->vec); + + while (finish_defs) { + deflected= pdDoDeflection(last, bp->pos, lastv, + bp->vec, dtime, bp->force, 0, + G.scene->r.cfra, ob->lay, &last_ob, &last_fc, &same_fc); + if (deflected) { + def_count = def_count + 1; + //deflection = 1; + if (def_count==10) finish_defs = 0; + } + else { + finish_defs = 0; + } + } + } +#endif /*other forces done*/ /* nice things could be done with anisotropic friction @@ -974,7 +1037,7 @@ void sbObjectReset(Object *ob) bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0f; // no idea about the Heun stuff! (ton) - VECCOPY(bp->prevpos, bp->vec); + VECCOPY(bp->prevpos, bp->pos); VECCOPY(bp->prevvec, bp->vec); VECCOPY(bp->prevdx, bp->vec); VECCOPY(bp->prevdv, bp->vec); @@ -987,6 +1050,7 @@ void sbObjectReset(Object *ob) void sbObjectStep(Object *ob, float framenr) { SoftBody *sb; + Base *base; float dtime; int timescale,t; float ctime, forcetime; @@ -1003,6 +1067,11 @@ void sbObjectStep(Object *ob, float framenr) /* still no points? go away */ if(sb->totpoint==0) return; + /* reset deflector cache, sumohandle is free, but its still sorta abuse... (ton) */ + for(base= G.scene->base.first; base; base= base->next) { + base->object->sumohandle= NULL; + } + /* checking time: */ ctime= bsystem_time(ob, NULL, framenr, 0.0); softbody_scale_time(steptime); // translate frames/sec and lenghts unit to SI system @@ -1124,5 +1193,14 @@ void sbObjectStep(Object *ob, float framenr) // so here it is ! softbody_to_object(ob); } + + /* reset deflector cache */ + for(base= G.scene->base.first; base; base= base->next) { + if(base->object->sumohandle) { + MEM_freeN(base->object->sumohandle); + base->object->sumohandle= NULL; + } + } + } diff --git a/source/blender/makesdna/DNA_effect_types.h b/source/blender/makesdna/DNA_effect_types.h index 86dd2f299c3..dc3118b7f73 100644 --- a/source/blender/makesdna/DNA_effect_types.h +++ b/source/blender/makesdna/DNA_effect_types.h @@ -67,11 +67,6 @@ #define WAV_Y 4 #define WAV_CYCL 8 - /* Effector Fields types */ -#define PFIELD_FORCE 1 -#define PFIELD_VORTEX 2 -#define PFIELD_MAGNET 3 - typedef struct Effect { struct Effect *next, *prev; short type, flag, buttype, rt; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index fb11938c442..1e1c0760889 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -80,17 +80,30 @@ typedef struct LBuf { } LBuf; typedef struct PartDeflect { - short deflect; /* Deflection flag - does mesh deflect particles*/ - short forcefield; /* Force flag, do the vertices attract / repel particles ? */ - - float pdef_damp; /* Damping factor for particle deflection */ - float pdef_rdamp; /* Random element of damping for deflection */ - float pdef_perm; /* Chance of particle passing through mesh */ + short deflect; /* Deflection flag - does mesh deflect particles*/ + short forcefield; /* Force field type, do the vertices attract / repel particles ? */ + short flag; /* general settings flag */ + short pad; + + float pdef_damp; /* Damping factor for particle deflection */ + float pdef_rdamp; /* Random element of damping for deflection */ + float pdef_perm; /* Chance of particle passing through mesh */ - float f_strength; /* The strength of the force (+ or - ) */ - float f_power; /* The power law - real gravitation is 2 (square) */ + float f_strength; /* The strength of the force (+ or - ) */ + float f_power; /* The power law - real gravitation is 2 (square) */ + float maxdist; /* if indicated, use this maximum */ } PartDeflect; +/* pd->forcefield: Effector Fields types */ +#define PFIELD_FORCE 1 +#define PFIELD_VORTEX 2 +#define PFIELD_MAGNET 3 +#define PFIELD_WIND 4 + +/* pd->flag: various settings */ +#define PFIELD_USEMAX 1 + + typedef struct SoftBody { /* dynamic data */ int totpoint, totspring; diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 7081e7540ac..2fe7b758eb6 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -1428,21 +1428,27 @@ static void object_panel_deflectors(Object *ob) } if(ob->pd) { + PartDeflect *pd= ob->pd; + uiBlockBeginAlign(block); + uiDefButS(block, ROW, REDRAWVIEW3D, "None", 10,160,50,20, &pd->forcefield, 1.0, 0, 0, 0, "No force"); + uiDefButS(block, ROW, REDRAWVIEW3D, "Wind", 60,160,50,20, &pd->forcefield, 1.0, PFIELD_WIND, 0, 0, "Constant force applied in direction of Object Z axis"); + uiDefButS(block, ROW, REDRAWVIEW3D, "Force field", 110,160,100,20, &pd->forcefield, 1.0, PFIELD_FORCE, 0, 0, "Object center attracts or repels particles"); + uiDefButS(block, ROW, REDRAWVIEW3D, "Vortex field", 210,160,100,20, &pd->forcefield, 1.0, PFIELD_VORTEX, 0, 0, "Particles swirl around Z-axis of the object"); - uiDefButS(block, ROW, REDRAWVIEW3D, "None", 10,160,200,20, &ob->pd->forcefield, 1.0, 0, 0, 0, "No force"); - uiDefButS(block, ROW, REDRAWVIEW3D, "Force field", 10,140,200,20, &ob->pd->forcefield, 1.0, PFIELD_FORCE, 0, 0, "Object center attracts or repels particles"); - uiDefButS(block, ROW, REDRAWVIEW3D, "Vortex field", 10,120,200,20, &ob->pd->forcefield, 1.0, PFIELD_VORTEX, 0, 0, "Particles swirl around Z-axis of the object"); + uiBlockBeginAlign(block); + uiDefButF(block, NUM, REDRAWVIEW3D, "Strength: ", 10,130,150,20, &pd->f_strength, -1000, 1000, 1000, 0, "Strength of force field"); + uiDefButF(block, NUM, REDRAWVIEW3D, "Fall-off: ", 160,130,150,20, &pd->f_power, 0, 10, 100, 0, "Falloff power (real gravitational fallof = 2)"); + uiDefButBitS(block, TOG, PFIELD_USEMAX, REDRAWVIEW3D, "Use MaxDist", 10,110,150,20, &pd->flag, 0.0, 0, 0, 0, "Use a maximum distance for the field to work"); + uiDefButF(block, NUM, REDRAWVIEW3D, "MaxDist: ", 160,110,150,20, &pd->maxdist, 0, 1000.0, 100, 0, "Maximum distance for the field to work"); - uiDefButF(block, NUM, REDRAWVIEW3D, "Strength: ", 10,100,200,20, &ob->pd->f_strength, -1000, 1000, 1000, 0, "Strength of force field"); - uiDefButF(block, NUM, REDRAWVIEW3D, "Fall-off: ", 10,80,200,20, &ob->pd->f_power, 0, 10, 100, 0, "Falloff power (real gravitational fallof = 2)"); /* only meshes collide now */ if(ob->type==OB_MESH) { uiBlockBeginAlign(block); - uiDefButS(block, TOG|BIT|0, B_DIFF, "Deflection",10,50,200,20, &ob->pd->deflect, 0, 0, 0, 0, "Deflects particles based on collision"); - uiDefButF(block, NUM, B_DIFF, "Damping: ", 10,30,200,20, &ob->pd->pdef_damp, 0.0, 1.0, 10, 0, "Amount of damping during particle collision"); - uiDefButF(block, NUM, B_DIFF, "Rnd Damping: ", 10,10,200,20, &ob->pd->pdef_rdamp, 0.0, 1.0, 10, 0, "Random variation of damping"); - uiDefButF(block, NUM, B_DIFF, "Permeability: ", 10,-10,200,20, &ob->pd->pdef_perm, 0.0, 1.0, 10, 0, "Chance that the particle will pass through the mesh"); + uiDefButS(block, TOG|BIT|0, B_DIFF, "Deflection",10,50,200,20, &pd->deflect, 0, 0, 0, 0, "Deflects particles based on collision"); + uiDefButF(block, NUM, B_DIFF, "Damping: ", 10,30,200,20, &pd->pdef_damp, 0.0, 1.0, 10, 0, "Amount of damping during particle collision"); + uiDefButF(block, NUM, B_DIFF, "Rnd Damping: ", 10,10,200,20, &pd->pdef_rdamp, 0.0, 1.0, 10, 0, "Random variation of damping"); + uiDefButF(block, NUM, B_DIFF, "Permeability: ", 10,-10,200,20, &pd->pdef_perm, 0.0, 1.0, 10, 0, "Chance that the particle will pass through the mesh"); } uiBlockEndAlign(block); } diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c index cc4a7043cde..309cc7b449e 100644 --- a/source/blender/src/drawobject.c +++ b/source/blender/src/drawobject.c @@ -2997,20 +2997,49 @@ static void drawmball(Object *ob, int dt) 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}; - if (ob->pd->forcefield == PFIELD_FORCE) { + /* calculus here, is reused in PFIELD_FORCE */ + mygetmatrix(tmat); + Mat4Invert(imat, tmat); +// 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(vec, pd->maxdist, imat); + setlinestyle(0); + } + if (pd->forcefield == PFIELD_WIND) { + float force_val; + + Mat4One(tmat); + BIF_ThemeColorBlend(TH_WIRE, 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); + else + force_val = pd->f_strength; + force_val*= 0.1; + drawcircball(vec, 1.0, tmat); + vec[2]= 0.5*force_val; + drawcircball(vec, 1.0, tmat); + vec[2]= 1.0*force_val; + drawcircball(vec, 1.0, tmat); + vec[2]= 1.5*force_val; + drawcircball(vec, 1.0, tmat); + + } + else if (pd->forcefield == PFIELD_FORCE) { float ffall_val; - mygetmatrix(tmat); - Mat4Invert(imat, tmat); - Normalise(imat[0]); - Normalise(imat[1]); if (has_ipo_code(ob->ipo, OB_PD_FFALL)) ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, G.scene->r.cfra); else - ffall_val = ob->pd->f_power; + ffall_val = pd->f_power; BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.5); drawcircball(vec, 1.0, imat); @@ -3019,19 +3048,19 @@ static void draw_forcefield(Object *ob) BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.9 - 0.4 / pow(2.0, (double)ffall_val)); drawcircball(vec, 2.0, imat); } - else if (ob->pd->forcefield == PFIELD_VORTEX) { + else if (pd->forcefield == PFIELD_VORTEX) { float ffall_val, force_val; Mat4One(imat); if (has_ipo_code(ob->ipo, OB_PD_FFALL)) ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, G.scene->r.cfra); else - ffall_val = ob->pd->f_power; + ffall_val = pd->f_power; if (has_ipo_code(ob->ipo, OB_PD_FSTR)) force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, G.scene->r.cfra); else - force_val = ob->pd->f_strength; + force_val = pd->f_strength; BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7); if (force_val < 0) { -- cgit v1.2.3