diff options
-rw-r--r-- | release/ui/buttons_particle.py | 62 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_particle.h | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/depsgraph.c | 15 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 26 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle.c | 669 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/particle_system.c | 279 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pointcache.c | 36 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 13 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 5 | ||||
-rw-r--r-- | source/blender/editors/space_buttons/buttons_intern.h | 4 | ||||
-rw-r--r-- | source/blender/editors/space_buttons/buttons_ops.c | 204 | ||||
-rw-r--r-- | source/blender/editors/space_buttons/space_buttons.c | 4 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/drawobject.c | 32 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_particle_types.h | 38 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_access.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_particle.c | 325 | ||||
-rw-r--r-- | source/blender/render/intern/source/convertblender.c | 20 |
17 files changed, 1093 insertions, 645 deletions
diff --git a/release/ui/buttons_particle.py b/release/ui/buttons_particle.py index ef7ede15d6e..2d269967e4b 100644 --- a/release/ui/buttons_particle.py +++ b/release/ui/buttons_particle.py @@ -131,6 +131,9 @@ class PARTICLE_PT_cache(ParticleButtonsPanel): psys = context.particle_system if psys==None: return False if psys.settings==None: return False + phystype = psys.settings.physics_type + if phystype == 'NO' or phystype == 'KEYED': + return False return psys.settings.type in ('EMITTER', 'REACTOR') def draw(self, context): @@ -277,16 +280,40 @@ class PARTICLE_PT_physics(ParticleButtonsPanel): sub.itemR(part, "acceleration") elif part.physics_type == 'KEYED': - sub.itemR(psys, "keyed_first") - if psys.keyed_first==True: - sub.itemR(psys, "timed_keys", text="Key timing") - else: - sub.itemR(part, "keyed_time") - sub = split.column() - sub.itemL(text="Next key from object:") - sub.itemR(psys, "keyed_object", text="") - sub.itemR(psys, "keyed_particle_system") - + row = layout.row() + col = row.column() + col.active = not psys.keyed_timing + col.itemR(part, "keyed_loops", text="Loops") + row.itemR(psys, "keyed_timing", text="Use Timing") + + layout.itemL(text="Keys:") + row = layout.row() + + row.template_list(psys, "keyed_targets", psys, "active_keyed_target_index") + + col = row.column() + subrow = col.row() + subcol = subrow.column(align=True) + subcol.itemO("PARTICLE_OT_new_keyed_target", icon="ICON_ZOOMIN", text="") + subcol.itemO("PARTICLE_OT_remove_keyed_target", icon="ICON_ZOOMOUT", text="") + subrow = col.row() + subcol = subrow.column(align=True) + subcol.itemO("PARTICLE_OT_keyed_target_move_up", icon="VICON_MOVE_UP", text="") + subcol.itemO("PARTICLE_OT_keyed_target_move_down", icon="VICON_MOVE_DOWN", text="") + + key = psys.active_keyed_target + if key: + row = layout.row() + col = row.column() + #doesn't work yet + #col.red_alert = key.valid + col.itemR(key, "object", text="") + col.itemR(key, "system", text="System") + col = row.column(); + col.active = psys.keyed_timing + col.itemR(key, "time") + col.itemR(key, "duration") + if part.physics_type=='NEWTON' or part.physics_type=='BOIDS': sub.itemR(part, "size_deflect") @@ -308,7 +335,7 @@ class PARTICLE_PT_render(ParticleButtonsPanel): psys = context.particle_system part = psys.settings - + row = layout.row() row.itemR(part, "material") row.itemR(psys, "parent"); @@ -336,7 +363,7 @@ class PARTICLE_PT_render(ParticleButtonsPanel): sub.itemR(part, "velocity_length") elif part.ren_as == 'PATH': - if (part.type!='HAIR' and psys.point_cache.baked==False): + if (part.type!='HAIR' and part.physics_type!='KEYED' and psys.point_cache.baked==False): box = layout.box() box.itemL(text="Baked or keyed particles needed for correct rendering.") return @@ -460,7 +487,7 @@ class PARTICLE_PT_draw(ParticleButtonsPanel): path = (part.ren_as=='PATH' and part.draw_as=='RENDER') or part.draw_as=='PATH' - if path and part.type!='HAIR' and psys.point_cache.baked==False: + if path and part.type!='HAIR' and part.physics_type!='KEYED' and psys.point_cache.baked==False: box = layout.box() box.itemL(text="Baked or keyed particles needed for correct drawing.") return @@ -549,6 +576,15 @@ class PARTICLE_PT_children(ParticleButtonsPanel): col.itemR(part, "rough2_size") col.itemR(part, "rough2_thres", slider=True) + row = layout.row() + col = row.column(align=True) + col.itemR(part, "child_length", slider=True) + col.itemR(part, "child_length_thres", slider=True) + + col = row.column(align=True) + col.itemL(text="Space reserved for") + col.itemL(text="hair parting controls") + layout.row().itemL(text="Kink:") layout.row().itemR(part, "kink", expand=True) diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index aa24706077d..bb0b905b8e3 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -260,7 +260,6 @@ void psys_flush_particle_settings(struct Scene *scene, struct ParticleSettings * void make_local_particlesettings(struct ParticleSettings *part); struct LinkNode *psys_using_settings(struct Scene *scene, struct ParticleSettings *part, int flush_update); -void psys_changed_type(struct ParticleSystem *psys); void psys_reset(struct ParticleSystem *psys, int mode); void psys_find_parents(struct Object *ob, struct ParticleSystemModifierData *psmd, struct ParticleSystem *psys); @@ -289,12 +288,14 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]); /* particle_system.c */ -int psys_count_keyed_targets(struct Object *ob, struct ParticleSystem *psys); +void psys_count_keyed_targets(struct Object *ob, struct ParticleSystem *psys); void psys_get_reactor_target(struct Object *ob, struct ParticleSystem *psys, struct Object **target_ob, struct ParticleSystem **target_psys); void psys_init_effectors(struct Scene *scene, struct Object *obsrc, struct Group *group, struct ParticleSystem *psys); void psys_end_effectors(struct ParticleSystem *psys); +void psys_make_temp_pointcache(struct Object *ob, struct ParticleSystem *psys); +void psys_end_temp_pointcache(struct ParticleSystem *psys); void psys_get_pointcache_start_end(struct Scene *scene, struct ParticleSystem *psys, int *sfra, int *efra); void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index de036e25d82..f52eec34cc7 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -562,10 +562,17 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O if(!psys_check_enabled(ob, psys)) continue; - if(part->phystype==PART_PHYS_KEYED && psys->keyed_ob && - BLI_findlink(&psys->keyed_ob->particlesystem,psys->keyed_psys-1)) { - node2 = dag_get_node(dag, psys->keyed_ob); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Keyed Physics"); + if(part->phystype==PART_PHYS_KEYED) { + KeyedParticleTarget *kpt = psys->keyed_targets.first; + + for(; kpt; kpt=kpt->next) { + if(kpt->ob && BLI_findlink(&kpt->ob->particlesystem, kpt->psys-1)) { + node2 = dag_get_node(dag, kpt->ob); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Keyed Physics"); + } + else + break; + } } if(part->ren_as == PART_DRAW_OB && part->dup_ob) { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 6490ff3c724..7d6a83d7900 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -427,17 +427,14 @@ void unlink_object(Scene *scene, Object *ob) if(obt->particlesystem.first) { ParticleSystem *tpsys= obt->particlesystem.first; for(; tpsys; tpsys=tpsys->next) { - if(tpsys->keyed_ob==ob) { - ParticleSystem *psys= BLI_findlink(&ob->particlesystem,tpsys->keyed_psys-1); - - if(psys && psys->keyed_ob) { - tpsys->keyed_ob= psys->keyed_ob; - tpsys->keyed_psys= psys->keyed_psys; + KeyedParticleTarget *kpt = tpsys->keyed_targets.first; + for(; kpt; kpt=kpt->next) { + if(kpt->ob==ob) { + BLI_remlink(&tpsys->keyed_targets, kpt); + MEM_freeN(kpt); + obt->recalc |= OB_RECALC_DATA; + break; } - else - tpsys->keyed_ob= NULL; - - obt->recalc |= OB_RECALC_DATA; } if(tpsys->target_ob==ob) { @@ -1050,18 +1047,23 @@ ParticleSystem *copy_particlesystem(ParticleSystem *psys) psysn= MEM_dupallocN(psys); psysn->particles= MEM_dupallocN(psys->particles); psysn->child= MEM_dupallocN(psys->child); + if(psysn->particles->keys) + psysn->particles->keys = MEM_dupallocN(psys->particles->keys); for(a=0, pa=psysn->particles; a<psysn->totpart; a++, pa++) { if(pa->hair) pa->hair= MEM_dupallocN(pa->hair); - if(pa->keys) - pa->keys= MEM_dupallocN(pa->keys); + if(a) + pa->keys= (pa-1)->keys + (pa-1)->totkey; } if(psys->soft) { psysn->soft= copy_softbody(psys->soft); psysn->soft->particles = psysn; } + + if(psys->keyed_targets.first) + BLI_duplicatelist(&psysn->keyed_targets, &psys->keyed_targets); psysn->pathcache= NULL; psysn->childcache= NULL; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 4488f8cdffd..cefeafcdd50 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -84,7 +84,8 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx, ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex); static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part, - ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, ParticleKey *state, float t); + ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, + float *orco, float mat[4][4], ParticleKey *state, float t); /* few helpers for countall etc. */ int count_particles(ParticleSystem *psys){ @@ -478,10 +479,16 @@ void psys_free(Object *ob, ParticleSystem * psys) if(psys->pointcache) BKE_ptcache_free(psys->pointcache); + if(psys->keyed_targets.first) + BLI_freelistN(&psys->keyed_targets); + MEM_freeN(psys); } } +/************************************************/ +/* Rendering */ +/************************************************/ /* these functions move away particle data and bring it back after * rendering, to make different render settings possible without * removing the previous data. this should be solved properly once */ @@ -889,7 +896,7 @@ int psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float } /************************************************/ -/* Interpolated Particles */ +/* Interpolation */ /************************************************/ static float interpolate_particle_value(float v1, float v2, float v3, float v4, float *w, int four) { @@ -938,6 +945,214 @@ void psys_interpolate_particle(short type, ParticleKey keys[4], float dt, Partic +typedef struct ParticleInterpolationData { + ParticleKey *kkey[2]; + HairKey *hkey[2]; + BodyPoint *bp[2]; + SoftBody *soft; + int keyed, cached; + float birthtime, dietime; +} ParticleInterpolationData; +/* Assumes pointcache->mem_cache exists, so for disk cached particles call psys_make_temp_pointcache() before use */ +static void get_pointcache_keys_for_time(Object *ob, ParticleSystem *psys, int index, float t, ParticleKey *key1, ParticleKey *key2) +{ + PointCache *cache = psys->pointcache; + static PTCacheMem *pm = NULL; /* not thread safe */ + + if(index < 0) { /* initialize */ + pm = cache->mem_cache.first; + + if(pm) + pm = pm->next; + } + else { + if(pm) { + while(pm && pm->next && (float)pm->frame < t) + pm = pm->next; + + copy_particle_key(key2, ((ParticleKey *)pm->data) + index, 1); + copy_particle_key(key1, ((ParticleKey *)(pm->prev)->data) + index, 1); + } + else if(cache->mem_cache.first) { + PTCacheMem *pm2 = cache->mem_cache.first; + copy_particle_key(key2, ((ParticleKey *)pm2->data) + index, 1); + copy_particle_key(key1, ((ParticleKey *)pm2->data) + index, 1); + } + } +} +static void init_particle_interpolation(Object *ob, ParticleSystem *psys, ParticleData *pa, ParticleInterpolationData *pind) +{ + + if(pind->keyed) { + pind->kkey[0] = pa->keys; + + if(pa->totkey > 1) + pind->kkey[1] = pa->keys + 1; + else + pind->kkey[1] = NULL; + + pind->birthtime = pa->keys->time; + pind->dietime = (pa->keys + pa->totkey - 1)->time; + } + else if(pind->cached) { + get_pointcache_keys_for_time(ob, psys, -1, 0.0f, NULL, NULL); + + pind->birthtime = pa->time; + pind->dietime = pa->dietime; + } + else { + pind->hkey[0] = pa->hair; + pind->hkey[1] = pa->hair + 1; + + pind->birthtime = pa->hair->time; + pind->dietime = (pa->hair + pa->totkey - 1)->time; + } + + if(pind->soft) { + pind->bp[0] = pind->soft->bpoint + pa->bpi; + pind->bp[1] = pind->soft->bpoint + pa->bpi + 1; + } +} +static void hair_to_particle(ParticleKey *key, HairKey *hkey) +{ + VECCOPY(key->co, hkey->co); + key->time = hkey->time; +} +static void bp_to_particle(ParticleKey *key, BodyPoint *bp, HairKey *hkey) +{ + VECCOPY(key->co, bp->pos); + key->time = hkey->time; +} + +static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData *pa, float t, float frs_sec, ParticleInterpolationData *pind, ParticleKey *result) +{ + ParticleKey keys[4]; + float real_t, dfra, keytime; + + /* interpret timing and find keys */ + if(pind->keyed) { + /* we have only one key, so let's use that */ + if(pind->kkey[1]==NULL) { + copy_particle_key(result, pind->kkey[0], 1); + return; + } + + if(result->time < 0.0f) + real_t = -result->time; + else + real_t = pind->kkey[0]->time + t * (pind->kkey[0][pa->totkey-1].time - pind->kkey[0]->time); + + if(psys->part->phystype==PART_PHYS_KEYED && psys->flag & PSYS_KEYED_TIMING) { + KeyedParticleTarget *kpt = psys->keyed_targets.first; + + kpt=kpt->next; + + while(kpt && pa->time + kpt->time < real_t) + kpt= kpt->next; + + if(kpt) { + kpt=kpt->prev; + + if(pa->time + kpt->time + kpt->duration > real_t) + real_t = pa->time + kpt->time; + } + else + real_t = pa->time + ((KeyedParticleTarget*)psys->keyed_targets.last)->time; + } + + CLAMP(real_t, pa->time, pa->dietime); + + while(pind->kkey[1]->time < real_t) + pind->kkey[1]++; + + pind->kkey[0] = pind->kkey[1] - 1; + } + else if(pind->cached) { + if(result->time < 0.0f) /* flag for time in frames */ + real_t = -result->time; + else + real_t = pa->time + t * (pa->dietime - pa->time); + } + else { + if(result->time < 0.0f) + real_t = -result->time; + else + real_t = pind->hkey[0]->time + t * (pind->hkey[0][pa->totkey-1].time - pind->hkey[0]->time); + + while(pind->hkey[1]->time < real_t) { + pind->hkey[1]++; + pind->bp[1]++; + } + + pind->hkey[0] = pind->hkey[1] - 1; + } + + /* set actual interpolation keys */ + if(pind->soft) { + pind->bp[0] = pind->bp[1] - 1; + bp_to_particle(keys + 1, pind->bp[0], pind->hkey[0]); + bp_to_particle(keys + 2, pind->bp[1], pind->hkey[1]); + } + else if(pind->keyed) { + memcpy(keys + 1, pind->kkey[0], sizeof(ParticleKey)); + memcpy(keys + 2, pind->kkey[1], sizeof(ParticleKey)); + } + else if(pind->cached) { + get_pointcache_keys_for_time(NULL, psys, p, real_t, keys+1, keys+2); + } + else { + hair_to_particle(keys + 1, pind->hkey[0]); + hair_to_particle(keys + 2, pind->hkey[1]); + } + + /* set secondary interpolation keys for hair */ + if(!pind->keyed && !pind->cached) { + if(pind->soft) { + if(pind->hkey[0] != pa->hair) + bp_to_particle(keys, pind->bp[0] - 1, pind->hkey[0] - 1); + else + bp_to_particle(keys, pind->bp[0], pind->hkey[0]); + } + else { + if(pind->hkey[0] != pa->hair) + hair_to_particle(keys, pind->hkey[0] - 1); + else + hair_to_particle(keys, pind->hkey[0]); + } + + if(pind->soft) { + if(pind->hkey[1] != pa->hair + pa->totkey - 1) + bp_to_particle(keys + 3, pind->bp[1] + 1, pind->hkey[1] + 1); + else + bp_to_particle(keys + 3, pind->bp[1], pind->hkey[1]); + } + else { + if(pind->hkey[1] != pa->hair + pa->totkey - 1) + hair_to_particle(keys + 3, pind->hkey[1] + 1); + else + hair_to_particle(keys + 3, pind->hkey[1]); + } + } + + dfra = keys[2].time - keys[1].time; + keytime = (real_t - keys[1].time) / dfra; + + /* convert velocity to timestep size */ + if(pind->keyed || pind->cached){ + VecMulf(keys[1].vel, dfra / frs_sec); + VecMulf(keys[2].vel, dfra / frs_sec); + QuatInterpol(result->rot,keys[1].rot,keys[2].rot,keytime); + } + + /* now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between [0,1]->[k2,k3] (k1 & k4 used for cardinal & bspline interpolation)*/ + psys_interpolate_particle((pind->keyed || pind->cached) ? -1 /* signal for cubic interpolation */ + : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL) + ,keys, keytime, result, 1); + + /* the velocity needs to be converted back from cubic interpolation */ + if(pind->keyed || pind->cached) + VecMulf(result->vel, frs_sec / dfra); +} /************************************************/ /* Particles on a dm */ /************************************************/ @@ -1438,16 +1653,6 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in /************************************************/ /* Path Cache */ /************************************************/ -static void hair_to_particle(ParticleKey *key, HairKey *hkey) -{ - VECCOPY(key->co, hkey->co); - key->time = hkey->time; -} -static void bp_to_particle(ParticleKey *key, BodyPoint *bp, HairKey *hkey) -{ - VECCOPY(key->co, bp->pos); - key->time = hkey->time; -} static float vert_weight(MDeformVert *dvert, int group) { MDeformWeight *dw; @@ -1734,7 +1939,7 @@ int do_guide(Scene *scene, ParticleKey *state, int pa_num, float time, ListBase } return 0; } -static void do_rough(float *loc, float t, float fac, float size, float thres, ParticleKey *state) +static void do_rough(float *loc, float mat[4][4], float t, float fac, float size, float thres, ParticleKey *state) { float rough[3]; float rco[3]; @@ -1747,32 +1952,24 @@ static void do_rough(float *loc, float t, float fac, float size, float thres, Pa rough[0]=-1.0f+2.0f*BLI_gTurbulence(size, rco[0], rco[1], rco[2], 2,0,2); rough[1]=-1.0f+2.0f*BLI_gTurbulence(size, rco[1], rco[2], rco[0], 2,0,2); rough[2]=-1.0f+2.0f*BLI_gTurbulence(size, rco[2], rco[0], rco[1], 2,0,2); - VECADDFAC(state->co,state->co,rough,fac); + + VECADDFAC(state->co,state->co,mat[0],fac*rough[0]); + VECADDFAC(state->co,state->co,mat[1],fac*rough[1]); + VECADDFAC(state->co,state->co,mat[2],fac*rough[2]); } -static void do_rough_end(float *loc, float t, float fac, float shape, ParticleKey *state, ParticleKey *par) +static void do_rough_end(float *loc, float mat[4][4], float t, float fac, float shape, ParticleKey *state) { - float rough[3], rnor[3]; + float rough[2]; float roughfac; roughfac=fac*(float)pow((double)t,shape); VECCOPY(rough,loc); rough[0]=-1.0f+2.0f*rough[0]; rough[1]=-1.0f+2.0f*rough[1]; - rough[2]=-1.0f+2.0f*rough[2]; VecMulf(rough,roughfac); - - if(par){ - VECCOPY(rnor,par->vel); - } - else{ - VECCOPY(rnor,state->vel); - } - Normalize(rnor); - Projf(rnor,rough,rnor); - VECSUB(rough,rough,rnor); - - VECADD(state->co,state->co,rough); + VECADDFAC(state->co,state->co,mat[0],rough[0]); + VECADDFAC(state->co,state->co,mat[1],rough[1]); } static void do_path_effectors(Scene *scene, Object *ob, ParticleSystem *psys, int i, ParticleCacheKey *ca, int k, int steps, float *rootco, float effector, float dfra, float cfra, float *length, float *vec) { @@ -2007,7 +2204,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, ParticleData *pa=NULL; ParticleTexture ptex; float *cpa_fuv=0, *par_rot=0; - float co[3], orco[3], ornor[3], t, cpa_1st[3], dvec[3]; + float co[3], orco[3], ornor[3], hairmat[4][4], t, cpa_1st[3], dvec[3]; float branch_begin, branch_end, branch_prob, rough_rand; float length, max_length = 1.0f, cur_length = 0.0f; float eff_length, eff_vec[3]; @@ -2065,8 +2262,6 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, cpa_num = cpa->num; foffset= cpa->foffset; - if(part->childtype == PART_CHILD_FACES) - foffset = -(2.0f + part->childspread); cpa_fuv = cpa->fuv; cpa_from = PART_FROM_FACE; @@ -2078,6 +2273,10 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, Mat4MulVecfl(ob->obmat,cpa_1st); } + pa = psys->particles + cpa->parent; + + psys_mat_hair_to_global(ob, ctx->psmd->dm, psys->part->from, pa, hairmat); + pa=0; } else{ @@ -2099,6 +2298,8 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, cpa_fuv=pa->fuv; psys_particle_on_emitter(ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,ornor,0,0,orco,0); + + psys_mat_hair_to_global(ob, ctx->psmd->dm, psys->part->from, pa, hairmat); } keys->steps = ctx->steps; @@ -2190,7 +2391,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, } /* apply different deformations to the child path */ - do_child_modifiers(ctx->scene, ob, psys, part, &ptex, (ParticleKey *)par, par_rot, cpa, orco, (ParticleKey *)state, t); + do_child_modifiers(ctx->scene, ob, psys, part, &ptex, (ParticleKey *)par, par_rot, cpa, orco, hairmat, (ParticleKey *)state, t); /* TODO: better branching */ //if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING) @@ -2247,20 +2448,12 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, /* check if path needs to be cut before actual end of data points */ if(k){ VECSUB(dvec,state->co,(state-1)->co); - if(part->flag&PART_ABS_LENGTH) - length=VecLength(dvec); - else - length=1.0f/(float)ctx->steps; - + length=1.0f/(float)ctx->steps; k=check_path_length(k,keys,state,max_length,&cur_length,length,dvec); } else{ /* initialize length calculation */ - if(part->flag&PART_ABS_LENGTH) - max_length= part->abslength*ptex.length; - else - max_length= ptex.length; - + max_length= ptex.length; cur_length= 0.0f; } @@ -2353,36 +2546,6 @@ void psys_cache_child_paths(Scene *scene, Object *ob, ParticleSystem *psys, floa psys_threads_free(pthreads); } -static void get_pointcache_keys_for_time(ParticleSystem *psys, int index, float t, ParticleKey *key1, ParticleKey *key2) -{ - PointCache *cache = psys->pointcache; - static PTCacheMem *pm = NULL; - - if(cache->flag & PTCACHE_DISK_CACHE) { - /* TODO */ - } - else { - if(index < 0) { /* initialize */ - pm = cache->mem_cache.first; - if(pm) - pm = pm->next; - } - else { - if(pm) { - while(pm && pm->next && (float)pm->frame < t) - pm = pm->next; - - copy_particle_key(key2, ((ParticleKey *)pm->data) + index, 1); - copy_particle_key(key1, ((ParticleKey *)(pm->prev)->data) + index, 1); - } - else if(cache->mem_cache.first) { - pm = cache->mem_cache.first; - copy_particle_key(key2, ((ParticleKey *)pm->data) + index, 1); - copy_particle_key(key1, ((ParticleKey *)pm->data) + index, 1); - } - } - } -} /* Calculates paths ready for drawing/rendering. */ /* -Usefull for making use of opengl vertex arrays for super fast strand drawing. */ /* -Makes child strands possible and creates them too into the cache. */ @@ -2395,7 +2558,7 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra ParticleSettings *part = psys->part; ParticleData *pa; - ParticleKey keys[4], result, *kkey[2] = {NULL, NULL}; + ParticleKey result, *kkey[2] = {NULL, NULL}; HairKey *hkey[2] = {NULL, NULL}; ParticleEdit *edit = 0; @@ -2405,11 +2568,14 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra BodyPoint *bp[2] = {NULL, NULL}; Material *ma; + + ParticleInterpolationData pind; float birthtime = 0.0, dietime = 0.0; float t, time = 0.0, keytime = 0.0, dfra = 1.0, frs_sec = scene->r.frs_sec; float col[4] = {0.5f, 0.5f, 0.5f, 1.0f}; float prev_tangent[3], hairmat[4][4]; + float rotmat[3][3]; int k,i; int steps = (int)pow(2.0, (double)psys->part->draw_step); int totpart = psys->totpart; @@ -2492,7 +2658,6 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra else memset(cache[i], 0, sizeof(*cache[i])*(steps+1)); if(!edit && !psys->totchild) { - //pa_length = part->length * (1.0f - part->randlength*pa->r_ave[0]); pa_length = 1.0f - part->randlength * 0.5 * (1.0f + pa->r_ave[0]); if(vg_length) pa_length *= psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_length); @@ -2504,38 +2669,27 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra ekey = edit->keys[i]; /*--get the first data points--*/ - if(keyed) { - kkey[0] = pa->keys; - kkey[1] = kkey[0] + 1; + pind.keyed = keyed; + pind.cached = baked; + pind.soft = soft; + init_particle_interpolation(ob, psys, pa, &pind); - birthtime = kkey[0]->time; - dietime = kkey[0][pa->totkey-1].time; - } - else if(baked) { - get_pointcache_keys_for_time(psys, -1, 0.0f, NULL, NULL); - - birthtime = pa->time; - dietime = pa->dietime; - } - else { - hkey[0] = pa->hair; - hkey[1] = hkey[0] + 1; - birthtime = hkey[0]->time; - dietime = hkey[0][pa->totkey-1].time; - - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); - } + /* hairmat is needed for for non-hair particle too so we get proper rotations */ + psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); + VECCOPY(rotmat[0], hairmat[2]); + VECCOPY(rotmat[1], hairmat[1]); + VECCOPY(rotmat[2], hairmat[0]); if(!edit) { if(part->draw & PART_ABS_PATH_TIME) { - birthtime = MAX2(birthtime, part->path_start); - dietime = MIN2(dietime, part->path_end); + birthtime = MAX2(pind.birthtime, part->path_start); + dietime = MIN2(pind.dietime, part->path_end); } else { - float tb = birthtime; - birthtime = tb + part->path_start * (dietime - tb); - dietime = tb + part->path_end * (dietime - tb); + float tb = pind.birthtime; + birthtime = tb + part->path_start * (pind.dietime - tb); + dietime = tb + part->path_end * (pind.dietime - tb); } if(birthtime >= dietime) { @@ -2546,101 +2700,18 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra dietime = birthtime + pa_length * (dietime - birthtime); } - if(soft){ - bp[0] = soft->bpoint + pa->bpi; - bp[1] = bp[0] + 1; - } - /*--interpolate actual path from data points--*/ for(k=0, ca=cache[i]; k<=steps; k++, ca++){ time = (float)k / (float)steps; t = birthtime + time * (dietime - birthtime); - if(keyed) { - while(kkey[1]->time < t) { - kkey[1]++; - } + result.time = -t; - kkey[0] = kkey[1] - 1; - } - else if(baked) { - get_pointcache_keys_for_time(psys, i, t, keys+1, keys+2); - } - else { - while(hkey[1]->time < t) { - hkey[1]++; - bp[1]++; - } - - hkey[0] = hkey[1] - 1; - } + do_particle_interpolation(psys, i, pa, t, frs_sec, &pind, &result); - if(soft) { - bp[0] = bp[1] - 1; - bp_to_particle(keys + 1, bp[0], hkey[0]); - bp_to_particle(keys + 2, bp[1], hkey[1]); - } - else if(keyed) { - memcpy(keys + 1, kkey[0], sizeof(ParticleKey)); - memcpy(keys + 2, kkey[1], sizeof(ParticleKey)); - } - else if(baked) - ; /* keys already set */ - else { - hair_to_particle(keys + 1, hkey[0]); - hair_to_particle(keys + 2, hkey[1]); - } - - - if(!keyed && !baked) { - if(soft) { - if(hkey[0] != pa->hair) - bp_to_particle(keys, bp[0] - 1, hkey[0] - 1); - else - bp_to_particle(keys, bp[0], hkey[0]); - } - else { - if(hkey[0] != pa->hair) - hair_to_particle(keys, hkey[0] - 1); - else - hair_to_particle(keys, hkey[0]); - } - - if(soft) { - if(hkey[1] != pa->hair + pa->totkey - 1) - bp_to_particle(keys + 3, bp[1] + 1, hkey[1] + 1); - else - bp_to_particle(keys + 3, bp[1], hkey[1]); - } - else { - if(hkey[1] != pa->hair + pa->totkey - 1) - hair_to_particle(keys + 3, hkey[1] + 1); - else - hair_to_particle(keys + 3, hkey[1]); - } - } - - dfra = keys[2].time - keys[1].time; - - keytime = (t - keys[1].time) / dfra; - - /* convert velocity to timestep size */ - if(keyed || baked){ - VecMulf(keys[1].vel, dfra / frs_sec); - VecMulf(keys[2].vel, dfra / frs_sec); - } - - /* now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between [0,1]->[k2,k3] (k1 & k4 used for cardinal & bspline interpolation)*/ - psys_interpolate_particle((keyed || baked) ? -1 /* signal for cubic interpolation */ - : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL) - ,keys, keytime, &result, 0); - - /* the velocity needs to be converted back from cubic interpolation */ - if(keyed || baked){ - VecMulf(result.vel, frs_sec / dfra); - } - else if(soft==NULL) { /* softbody and keyed are allready in global space */ + /* keyed, baked and softbody are allready in global space */ + if(!keyed && !baked && !soft) { Mat4MulVecfl(hairmat, result.co); } @@ -2678,8 +2749,9 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra VECCOPY(ca->col, col); } } + - /*--modify paths--*/ + /*--modify paths and calculate rotation & velocity--*/ VecSubf(vec,(cache[i]+1)->co,cache[i]->co); length = VecLength(vec); @@ -2708,12 +2780,18 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra float cosangle, angle, tangent[3], normal[3], q[4]; if(k == 1) { + /* calculate initial tangent for incremental rotations */ VECSUB(tangent, ca->co, (ca - 1)->co); - - vectoquat(tangent, OB_POSX, OB_POSZ, (ca-1)->rot); - VECCOPY(prev_tangent, tangent); Normalize(prev_tangent); + + /* First rotation is based on emitting face orientation. */ + /* This is way better than having flipping rotations resulting */ + /* from using a global axis as a rotation pole (vec_to_quat()). */ + /* It's not an ideal solution though since it disregards the */ + /* initial tangent, but taking that in to account will allow */ + /* the possibility of flipping again. -jahka */ + Mat3ToQuat_is_ok(rotmat, (ca-1)->rot); } else { VECSUB(tangent, ca->co, (ca - 1)->co); @@ -2780,15 +2858,6 @@ void copy_particle_key(ParticleKey *to, ParticleKey *from, int time){ memcpy(to,from,sizeof(ParticleKey)); to->time=to_time; } - /* - VECCOPY(to->co,from->co); - VECCOPY(to->vel,from->vel); - QUATCOPY(to->rot,from->rot); - if(time) - to->time=from->time; - to->flag=from->flag; - to->sbw=from->sbw; - */ } void psys_get_from_key(ParticleKey *key, float *loc, float *vel, float *rot, float *time){ if(loc) VECCOPY(loc,key->co); @@ -3017,8 +3086,6 @@ static void default_particle_settings(ParticleSettings *part) part->totpart= 1000; part->grid_res= 10; part->timetweak= 1.0; - part->keyed_time= 0.5; - //part->userjit; part->integrator= PART_INT_MIDPOINT; part->phystype= PART_PHYS_NEWTON; @@ -3032,7 +3099,6 @@ static void default_particle_settings(ParticleSettings *part) part->reactevent= PART_EVENT_DEATH; part->disp=100; part->from= PART_FROM_FACE; - part->length= 1.0; part->nbetween= 4; part->boidneighbours= 5; @@ -3059,10 +3125,15 @@ static void default_particle_settings(ParticleSettings *part) part->rough2_size=1.0; part->rough_end_shape=1.0; + part->clength=1.0f; + part->clength_thres=0.0f; + part->draw_line[0]=0.5; part->path_start = 0.0f; part->path_end = 1.0f; + part->keyed_loops = 1; + part->banking=1.0; part->max_bank=1.0; @@ -3480,7 +3551,7 @@ float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra, } static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx, ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex) { - ptex->length=part->length*(1.0f - part->randlength*cpa->rand[0]); + ptex->length= 1.0f - part->randlength*cpa->rand[0]; ptex->clump=1.0; ptex->kink=1.0; ptex->rough1= 1.0; @@ -3489,6 +3560,8 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread ptex->exist= 1.0; ptex->effector= 1.0; + ptex->length*= part->clength_thres < cpa->rand[1] ? part->clength : 1.0f; + get_cpa_texture(ctx->dm,ctx->ma,cpa_num,cpa_fuv,orco,ptex, MAP_PA_DENS|MAP_PA_LENGTH|MAP_PA_CLUMP|MAP_PA_KINK|MAP_PA_ROUGH); @@ -3511,7 +3584,7 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread if(ctx->vg_effector) ptex->effector*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_effector); } -static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part, ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, ParticleKey *state, float t) +static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part, ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, float mat[4][4], ParticleKey *state, float t) { int guided = 0; @@ -3528,13 +3601,13 @@ static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, P } if(part->rough1 != 0.0 && ptex->rough1 != 0.0) - do_rough(orco, t, ptex->rough1*part->rough1, part->rough1_size, 0.0, state); + do_rough(orco, mat, t, ptex->rough1*part->rough1, part->rough1_size, 0.0, state); if(part->rough2 != 0.0 && ptex->rough2 != 0.0) - do_rough(cpa->rand, t, ptex->rough2*part->rough2, part->rough2_size, part->rough2_thres, state); + do_rough(cpa->rand, mat, t, ptex->rough2*part->rough2, part->rough2_size, part->rough2_thres, state); if(part->rough_end != 0.0 && ptex->roughe != 0.0) - do_rough_end(cpa->rand, t, ptex->roughe*part->rough_end, part->rough_end_shape, state, par); + do_rough_end(cpa->rand, mat, t, ptex->roughe*part->rough_end, part->rough_end_shape, state); } /* get's hair (or keyed) particles state at the "path time" specified in state->time */ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, int p, ParticleKey *state, int vel) @@ -3549,8 +3622,9 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i HairKey *hkey[2] = {NULL, NULL}; ParticleKey *par=0, keys[4], tstate; ParticleThreadContext ctx; /* fake thread context for child modifiers */ + ParticleInterpolationData pind; - float t, real_t, dfra, keytime, frs_sec = scene->r.frs_sec; + float t, frs_sec = scene->r.frs_sec; float co[3], orco[3]; float hairmat[4][4]; int totparent = 0; @@ -3558,7 +3632,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i int totchild = psys->totchild; short between = 0, edit = 0; - int keyed = psys->flag & PSYS_KEYED; + int keyed = part->phystype & PART_PHYS_KEYED && psys->flag & PSYS_KEYED; int cached = !keyed && part->type != PART_HAIR; float *cpa_fuv; int cpa_num; short cpa_from; @@ -3580,88 +3654,14 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i key_from_object(pa->stick_ob,state); return; } - - if(keyed) { - kkey[0] = pa->keys; - kkey[1] = kkey[0] + 1; - if(state->time < 0.0f) - real_t = -state->time; - else - real_t = kkey[0]->time + t * (kkey[0][pa->totkey-1].time - kkey[0]->time); - } - else if(cached) { - get_pointcache_keys_for_time(psys, -1, 0.0f, NULL, NULL); - } - else { - hkey[0] = pa->hair; - hkey[1] = pa->hair + 1; - - if(state->time < 0.0f) - real_t = -state->time; - else - real_t = hkey[0]->time + t * (hkey[0][pa->totkey-1].time - hkey[0]->time); - } - - if(keyed) { - while(kkey[1]->time < real_t) { - kkey[1]++; - } - kkey[0] = kkey[1] - 1; - - memcpy(keys + 1, kkey[0], sizeof(ParticleKey)); - memcpy(keys + 2, kkey[1], sizeof(ParticleKey)); - } - else if(cached) { - if(state->time < 0.0f) /* flag for time in frames */ - real_t = -state->time; - else - real_t = pa->time + t * (pa->dietime - pa->time); - - get_pointcache_keys_for_time(psys, p, real_t, keys+1, keys+2); - } - else { - while(hkey[1]->time < real_t) - hkey[1]++; - - hkey[0] = hkey[1] - 1; - - hair_to_particle(keys + 1, hkey[0]); - hair_to_particle(keys + 2, hkey[1]); - } + pind.keyed = keyed; + pind.cached = cached; + pind.soft = NULL; + init_particle_interpolation(ob, psys, pa, &pind); + do_particle_interpolation(psys, p, pa, t, frs_sec, &pind, state); if(!keyed && !cached) { - if(hkey[0] != pa->hair) - hair_to_particle(keys, hkey[0] - 1); - else - hair_to_particle(keys, hkey[0]); - - if(hkey[1] != pa->hair + pa->totkey - 1) - hair_to_particle(keys + 3, hkey[1] + 1); - else - hair_to_particle(keys + 3, hkey[1]); - } - - dfra = keys[2].time - keys[1].time; - - keytime = (real_t - keys[1].time) / dfra; - - /* convert velocity to timestep size */ - if(keyed || cached){ - VecMulf(keys[1].vel, dfra / frs_sec); - VecMulf(keys[2].vel, dfra / frs_sec); - QuatInterpol(state->rot,keys[1].rot,keys[2].rot,keytime); - } - - psys_interpolate_particle((keyed || cached) ? -1 /* signal for cubic interpolation */ - : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL) - ,keys, keytime, state, 1); - - /* the velocity needs to be converted back from cubic interpolation */ - if(keyed || cached){ - VecMulf(state->vel, frs_sec / dfra); - } - else { if((pa->flag & PARS_REKEY)==0) { psys_mat_hair_to_global(ob, psmd->dm, part->from, pa, hairmat); Mat4MulVecfl(hairmat, state->co); @@ -3709,8 +3709,6 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i cpa_num=cpa->num; foffset= cpa->foffset; - if(part->childtype == PART_CHILD_FACES) - foffset = -(2.0f + part->childspread); cpa_fuv = cpa->fuv; cpa_from = PART_FROM_FACE; @@ -3721,11 +3719,14 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i //Mat4MulVecfl(ob->obmat,cpa_1st); + pa = psys->particles + cpa->parent; + + psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); + pa=0; } else{ /* get the parent state */ - keys->time = state->time; psys_get_particle_on_path(scene, ob, psys, cpa->parent, keys,1); @@ -3737,6 +3738,8 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i cpa_fuv=pa->fuv; psys_particle_on_emitter(psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,0,0,0,orco,0); + + psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); } /* correct child ipo timing */ @@ -3785,7 +3788,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i copy_particle_key(&tstate, state, 1); /* apply different deformations to the child path */ - do_child_modifiers(scene, ob, psys, part, &ptex, par, par->rot, cpa, orco, state, t); + do_child_modifiers(scene, ob, psys, part, &ptex, par, par->rot, cpa, orco, hairmat, state, t); /* try to estimate correct velocity */ if(vel){ @@ -3856,7 +3859,7 @@ int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psy state->time= (cfra-(part->sta+(part->end-part->sta)*cpa->rand[0]))/(part->lifetime*cpa->rand[1]); } else - state->time= (cfra-pa->time)/(pa->dietime-pa->time); + state->time= -cfra; psys_get_particle_on_path(scene, ob, psys, p, state,1); return 1; @@ -3893,57 +3896,55 @@ int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psy calc_latt_deform(psys->lattice, state->co,1.0f); } else{ - if (pa) { /* TODO PARTICLE - should this ever be NULL? - Campbell */ - if(pa->state.time==state->time || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED)) - copy_particle_key(state, &pa->state, 1); - else if(pa->prev_state.time==state->time) - copy_particle_key(state, &pa->prev_state, 1); - else { - /* let's interpolate to try to be as accurate as possible */ - if(pa->state.time + 1.0f > state->time && pa->prev_state.time - 1.0f < state->time) { - ParticleKey keys[4]; - float dfra, keytime, frs_sec = scene->r.frs_sec; + if(pa->state.time==state->time || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED)) + copy_particle_key(state, &pa->state, 1); + else if(pa->prev_state.time==state->time) + copy_particle_key(state, &pa->prev_state, 1); + else { + /* let's interpolate to try to be as accurate as possible */ + if(pa->state.time + 1.0f > state->time && pa->prev_state.time - 1.0f < state->time) { + ParticleKey keys[4]; + float dfra, keytime, frs_sec = scene->r.frs_sec; - if(pa->prev_state.time >= pa->state.time) { - /* prev_state is wrong so let's not use it, this can happen at frame 1 or particle birth */ - copy_particle_key(state, &pa->state, 1); + if(pa->prev_state.time >= pa->state.time) { + /* prev_state is wrong so let's not use it, this can happen at frame 1 or particle birth */ + copy_particle_key(state, &pa->state, 1); - VECADDFAC(state->co, state->co, state->vel, (state->time-pa->state.time)/frs_sec); - } - else { - copy_particle_key(keys+1, &pa->prev_state, 1); - copy_particle_key(keys+2, &pa->state, 1); + VECADDFAC(state->co, state->co, state->vel, (state->time-pa->state.time)/frs_sec); + } + else { + copy_particle_key(keys+1, &pa->prev_state, 1); + copy_particle_key(keys+2, &pa->state, 1); - dfra = keys[2].time - keys[1].time; + dfra = keys[2].time - keys[1].time; - keytime = (state->time - keys[1].time) / dfra; + keytime = (state->time - keys[1].time) / dfra; - /* convert velocity to timestep size */ - VecMulf(keys[1].vel, dfra / frs_sec); - VecMulf(keys[2].vel, dfra / frs_sec); - - psys_interpolate_particle(-1, keys, keytime, state, 1); - - /* convert back to real velocity */ - VecMulf(state->vel, frs_sec / dfra); + /* convert velocity to timestep size */ + VecMulf(keys[1].vel, dfra / frs_sec); + VecMulf(keys[2].vel, dfra / frs_sec); + + psys_interpolate_particle(-1, keys, keytime, state, 1); + + /* convert back to real velocity */ + VecMulf(state->vel, frs_sec / dfra); - VecLerpf(state->ave, keys[1].ave, keys[2].ave, keytime); - QuatInterpol(state->rot, keys[1].rot, keys[2].rot, keytime); - } - } - else { - /* extrapolating over big ranges is not accurate so let's just give something close to reasonable back */ - copy_particle_key(state, &pa->state, 0); + VecLerpf(state->ave, keys[1].ave, keys[2].ave, keytime); + QuatInterpol(state->rot, keys[1].rot, keys[2].rot, keytime); } } - - if(pa->alive==PARS_DEAD && part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob){ - key_from_object(pa->stick_ob,state); + else { + /* extrapolating over big ranges is not accurate so let's just give something close to reasonable back */ + copy_particle_key(state, &pa->state, 0); } + } - if(psys->lattice) - calc_latt_deform(psys->lattice, state->co,1.0f); + if(pa->alive==PARS_DEAD && part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob){ + key_from_object(pa->stick_ob,state); } + + if(psys->lattice) + calc_latt_deform(psys->lattice, state->co,1.0f); } return 1; diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 07e0e82a86d..56ca3e8e22b 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -111,10 +111,7 @@ static int get_current_display_percentage(ParticleSystem *psys) return 100; if(part->phystype==PART_PHYS_KEYED){ - if(psys->flag & PSYS_FIRST_KEYED) - return psys->part->disp; - else - return 100; + return psys->part->disp; } else return psys->part->disp; @@ -199,7 +196,7 @@ static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) if(psys->particles->keys) MEM_freeN(psys->particles->keys); - for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++) + for(i=0, pa=newpars; i<totsaved; i++, pa++) if(pa->keys) { pa->keys= NULL; pa->totkey= 0; @@ -1976,64 +1973,59 @@ static void reset_all_particles(Scene *scene, Object *ob, ParticleSystem *psys, /************************************************/ /* Keyed particles */ /************************************************/ -/* a bit of an unintuitive function :) counts objects in a keyed chain and returns 1 if some of them were selected (used in drawing) */ -int psys_count_keyed_targets(Object *ob, ParticleSystem *psys) +/* Counts valid keyed targets */ +void psys_count_keyed_targets(Object *ob, ParticleSystem *psys) { - ParticleSystem *kpsys=psys,*tpsys; - ParticleSettings *tpart; - Object *kob=ob,*tob; - int select=ob->flag&SELECT; - short totkeyed=0; - Base *base; - - ListBase lb; - lb.first=lb.last=0; - - tob=psys->keyed_ob; - while(tob){ - if((tpsys=BLI_findlink(&tob->particlesystem,kpsys->keyed_psys-1))){ - tpart=tpsys->part; - - if(tpart->phystype==PART_PHYS_KEYED){ - if(lb.first){ - for(base=lb.first;base;base=base->next){ - if(tob==base->object){ - fprintf(stderr,"Error: loop in keyed chain!\n"); - BLI_freelistN(&lb); - return select; - } - } - } - base=MEM_callocN(sizeof(Base), "keyed base"); - base->object=tob; - BLI_addtail(&lb,base); - - if(tob->flag&SELECT) - select++; - kob=tob; - kpsys=tpsys; - tob=tpsys->keyed_ob; - totkeyed++; + ParticleSystem *kpsys; + KeyedParticleTarget *kpt = psys->keyed_targets.first; + int psys_num = BLI_findindex(&ob->particlesystem, psys); + int keys_valid = 1; + psys->totkeyed = 0; + + for(; kpt; kpt=kpt->next) { + kpsys = NULL; + if(kpt->ob==ob || kpt->ob==NULL) { + if(kpt->psys >= psys_num) + kpsys = BLI_findlink(&ob->particlesystem, kpt->psys-1); + + if(kpsys && kpsys->totpart) { + kpt->flag |= KEYED_TARGET_VALID; + psys->totkeyed += keys_valid; + if(psys->flag & PSYS_KEYED_TIMING && kpt->duration != 0.0f) + psys->totkeyed += 1; } - else{ - tob=0; - totkeyed++; + else { + kpt->flag &= ~KEYED_TARGET_VALID; + keys_valid = 0; + } + } + else { + if(kpt->ob) + kpsys = BLI_findlink(&kpt->ob->particlesystem, kpt->psys-1); + + if(kpsys && kpsys->totpart) { + kpt->flag |= KEYED_TARGET_VALID; + psys->totkeyed += keys_valid; + if(psys->flag & PSYS_KEYED_TIMING && kpt->duration != 0.0f) + psys->totkeyed += 1; + } + else { + kpt->flag &= ~KEYED_TARGET_VALID; + keys_valid = 0; } } - else - tob=0; } - psys->totkeyed=totkeyed; - BLI_freelistN(&lb); - return select; + + psys->totkeyed *= psys->flag & PSYS_KEYED_TIMING ? 1 : psys->part->keyed_loops; } static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys) { Object *kob = ob; ParticleSystem *kpsys = psys; + KeyedParticleTarget *kpt; ParticleData *pa; - int totpart = psys->totpart, i, k, totkeys = psys->totkeyed + 1; + int totpart = psys->totpart, i, k, totkeys = psys->totkeyed; float prevtime, nexttime, keyedtime; /* no proper targets so let's clear and bail out */ @@ -2046,7 +2038,7 @@ static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys) if(totpart && psys->particles->totkey != totkeys) { free_keyed_keys(psys); - psys->particles->keys = MEM_callocN(psys->totpart*totkeys*sizeof(ParticleKey), "Keyed keys"); + psys->particles->keys = MEM_callocN(totpart*totkeys*sizeof(ParticleKey), "Keyed keys"); psys->particles->totkey = totkeys; for(i=1, pa=psys->particles+1; i<totpart; i++,pa++){ @@ -2057,32 +2049,36 @@ static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys) psys->flag &= ~PSYS_KEYED; + + kpt = psys->keyed_targets.first; for(k=0; k<totkeys; k++) { + if(kpt->ob) + kpsys = BLI_findlink(&kpt->ob->particlesystem, kpt->psys - 1); + else + kpsys = BLI_findlink(&ob->particlesystem, kpt->psys - 1); + for(i=0,pa=psys->particles; i<totpart; i++, pa++) { (pa->keys + k)->time = -1.0; /* use current time */ - if(kpsys->totpart > 0) - psys_get_particle_state(scene, kob, kpsys, i%kpsys->totpart, pa->keys + k, 1); + psys_get_particle_state(scene, kpt->ob, kpsys, i%kpsys->totpart, pa->keys + k, 1); - if(k==0) - pa->keys->time = pa->time; - else if(k==totkeys-1) - (pa->keys + k)->time = pa->time + pa->lifetime; - else{ - if(psys->flag & PSYS_KEYED_TIME){ - prevtime = (pa->keys + k - 1)->time; - nexttime = pa->time + pa->lifetime; - keyedtime = kpsys->part->keyed_time; - (pa->keys + k)->time = (1.0f - keyedtime) * prevtime + keyedtime * nexttime; + if(psys->flag & PSYS_KEYED_TIMING){ + (pa->keys+k)->time = pa->time + kpt->time; + if(kpt->duration != 0.0f && k+1 < totkeys) { + copy_particle_key(pa->keys+k+1, pa->keys+k, 1); + (pa->keys+k+1)->time = pa->time + kpt->time + kpt->duration; } - else - (pa->keys+k)->time = pa->time + (float)k / (float)(totkeys - 1) * pa->lifetime; } + else if(totkeys > 1) + (pa->keys+k)->time = pa->time + (float)k / (float)(totkeys - 1) * pa->lifetime; + else + pa->keys->time = pa->time; } - if(kpsys->keyed_ob){ - kob = kpsys->keyed_ob; - kpsys = BLI_findlink(&kob->particlesystem, kpsys->keyed_psys - 1); - } + + if(psys->flag & PSYS_KEYED_TIMING && kpt->duration!=0.0f) + k++; + + kpt = (kpt->next && kpt->next->flag & KEYED_TARGET_VALID) ? kpt = kpt->next : psys->keyed_targets.first; } psys->flag |= PSYS_KEYED; @@ -2198,6 +2194,60 @@ void psys_get_reactor_target(Object *ob, ParticleSystem *psys, Object **target_o /************************************************/ /* Point Cache */ /************************************************/ +void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys) +{ + PointCache *cache = psys->pointcache; + PTCacheFile *pf = NULL; + PTCacheMem *pm = NULL; + PTCacheID pid; + int cfra, sfra = cache->startframe, efra = cache->endframe; + int totelem = psys->totpart; + int float_count = sizeof(ParticleKey) / sizeof(float); + int tot = totelem * float_count; + + if((cache->flag & PTCACHE_DISK_CACHE)==0 || cache->mem_cache.first) + return; + + BKE_ptcache_id_from_particles(&pid, ob, psys); + + for(cfra=sfra; cfra <= efra; cfra++) { + pf = BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, cfra); + + if(pf) { + pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache temp mem"); + pm->data = MEM_callocN(sizeof(float)*tot, "Pointcache temp mem data"); + + if(fread(pm->data, sizeof(float), tot, pf->fp)!= tot) { + printf("Error reading from disk cache\n"); + + MEM_freeN(pm->data); + MEM_freeN(pm); + BKE_ptcache_file_close(pf); + return; + } + + pm->frame = cfra; + pm->totpoint = totelem; + + BLI_addtail(&cache->mem_cache, pm); + + BKE_ptcache_file_close(pf); + } + } +} +void psys_clear_temp_pointcache(ParticleSystem *psys) +{ + PTCacheMem *pm = psys->pointcache->mem_cache.first; + + if((psys->pointcache->flag & PTCACHE_DISK_CACHE)==0) + return; + + for(; pm; pm=pm->next) { + MEM_freeN(pm->data); + } + + BLI_freelistN(&psys->pointcache->mem_cache); +} void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra, int *efra) { ParticleSettings *part = psys->part; @@ -3912,61 +3962,6 @@ static void boid_body(Scene *scene, BoidVecFunc *bvf, ParticleData *pa, Particle if(part->flag & PART_BOIDS_2D){ pa->state.vel[2]=0.0; pa->state.co[2]=part->groundz; - - if(psys->keyed_ob && (psys->keyed_ob->type == OB_MESH)){ - Object *zob=psys->keyed_ob; - int min_face; - float co1[3],co2[3],min_d=2.0,min_w[4],imat[4][4]; - VECCOPY(co1,pa->state.co); - VECCOPY(co2,pa->state.co); - - co1[2]=1000.0f; - co2[2]=-1000.0f; - - Mat4Invert(imat,zob->obmat); - Mat4MulVecfl(imat,co1); - Mat4MulVecfl(imat,co2); - - if(psys_intersect_dm(scene,zob,0,0,co1,co2,&min_d,&min_face,min_w,0,0,0,0)){ - DerivedMesh *dm; - MFace *mface; - MVert *mvert; - float loc[3],nor[3],q1[4]; - - psys_disable_all(zob); - dm=mesh_get_derived_final(scene, zob, 0); - psys_enable_all(zob); - - mface=dm->getFaceDataArray(dm,CD_MFACE); - mface+=min_face; - mvert=dm->getVertDataArray(dm,CD_MVERT); - - /* get deflection point & normal */ - psys_interpolate_face(mvert,mface,0,0,min_w,loc,nor,0,0,0,0); - - Mat4MulVecfl(zob->obmat,loc); - Mat4Mul3Vecfl(zob->obmat,nor); - - Normalize(nor); - - VECCOPY(pa->state.co,loc); - - zvec[2]=1.0; - - Crossf(loc,zvec,nor); - - bank=VecLength(loc); - if(bank>0.0){ - bank=saasin(bank); - - VecRotToQuat(loc,bank,q); - - QUATCOPY(q1,pa->state.rot); - - QuatMul(pa->state.rot,q,q1); - } - } - } } length=bvf->Length(pa->state.vel); @@ -4238,7 +4233,7 @@ static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModif if((psys->part->childtype && psys->totchild != get_psys_tot_child(scene, psys)) || psys->recalc&PSYS_RECALC_RESET) alloc=1; - if(alloc || psys->recalc&PSYS_RECALC_RESET || (psys->vgroup[PSYS_VG_DENSITY] && (G.f & G_WEIGHTPAINT))) + if(alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (G.f & G_WEIGHTPAINT))) distr=1; if(distr){ @@ -4416,12 +4411,15 @@ static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *ps MEM_freeN(vg_size); } -void psys_changed_type(ParticleSystem *psys) +static void psys_changed_type(Object *ob, ParticleSystem *psys) { ParticleSettings *part; + PTCacheID pid; part= psys->part; + BKE_ptcache_id_from_particles(&pid, ob, psys); + /* system type has changed so set sensible defaults and clear non applicable flags */ if(part->from == PART_FROM_PARTICLE) { if(part->type != PART_REACTOR) @@ -4430,7 +4428,7 @@ void psys_changed_type(ParticleSystem *psys) part->distr = PART_DISTR_JIT; } - if(psys->part->phystype != PART_PHYS_KEYED) + if(part->phystype != PART_PHYS_KEYED) psys->flag &= ~PSYS_KEYED; if(part->type == PART_HAIR) { @@ -4442,6 +4440,8 @@ void psys_changed_type(ParticleSystem *psys) CLAMP(part->path_start, 0.0f, 100.0f); CLAMP(part->path_end, 0.0f, 100.0f); + + BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); } else { free_hair(psys, 1); @@ -4454,7 +4454,18 @@ void psys_changed_type(ParticleSystem *psys) psys_reset(psys, PSYS_RESET_ALL); } - +void psys_changed_physics(Object *ob, ParticleSystem *psys) +{ + if(ELEM(psys->part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) { + PTCacheID pid; + BKE_ptcache_id_from_particles(&pid, ob, psys); + BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); + } + else { + free_keyed_keys(psys); + psys->flag &= ~PSYS_KEYED; + } +} static void particles_fluid_step(Scene *scene, Object *ob, ParticleSystem *psys, int cfra) { if(psys->particles){ @@ -4588,6 +4599,8 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle BKE_ptcache_id_from_particles(&pid, ob, psys); BKE_ptcache_id_time(&pid, scene, 0.0f, &startframe, &endframe, NULL); + psys_clear_temp_pointcache(psys); + /* update ipo's */ #if 0 // XXX old animation system if((part->flag & PART_ABS_TIME) && part->ipo) { @@ -4736,7 +4749,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle if(usecache && psys->cfra == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) write_particles_to_cache(ob, psys, startframe); - if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) + if(part->phystype==PART_PHYS_KEYED) psys_count_keyed_targets(ob,psys); /* initialize vertex groups */ @@ -4783,7 +4796,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle write_particles_to_cache(ob, psys, framenr); /* for keyed particles the path is allways known so it can be drawn */ - if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED){ + if(part->phystype==PART_PHYS_KEYED) { set_keyed_keys(scene, ob, psys); psys_update_path_cache(scene, ob, psmd, psys,(int)cfra); } @@ -4866,7 +4879,9 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) return; if(psys->recalc & PSYS_RECALC_TYPE) - psys_changed_type(psys); + psys_changed_type(ob, psys); + else if(psys->recalc & PSYS_RECALC_PHYS) + psys_changed_physics(ob, psys); /* (re-)create hair */ if(psys->part->type==PART_HAIR && hair_needs_recalc(psys)) { diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 2fe46be7a89..6107510fa47 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -315,8 +315,10 @@ static int ptcache_pid_totelem(PTCacheID *pid) ParticleSystem *psys = pid->data; return psys->totpart; } - else if(pid->type==PTCACHE_TYPE_CLOTH) - return 0; // TODO + else if(pid->type==PTCACHE_TYPE_CLOTH) { + ClothModifierData *clmd = pid->data; + return clmd->clothObject->numverts; + } return 0; } @@ -429,6 +431,7 @@ int BKE_ptcache_read_cache(PTCacheReader *reader) if(pf) { BKE_ptcache_file_close(pf); + pf = NULL; MEM_freeN(data); } @@ -523,7 +526,9 @@ int BKE_ptcache_read_cache(PTCacheReader *reader) if(pf) { BKE_ptcache_file_close(pf); + pf = NULL; BKE_ptcache_file_close(pf2); + pf2 = NULL; MEM_freeN(data1); MEM_freeN(data2); } @@ -567,10 +572,13 @@ int BKE_ptcache_read_cache(PTCacheReader *reader) if(pf) { BKE_ptcache_file_close(pf); + pf = NULL; MEM_freeN(data); } - if(pf2) + if(pf2) { BKE_ptcache_file_close(pf2); + pf = NULL; + } ret = PTCACHE_READ_OLD; } @@ -602,13 +610,15 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer) PTCacheFile *pf= NULL; int elemsize = ptcache_pid_elemsize(writer->pid); int i, incr = elemsize / sizeof(float); - int add = 0, overwrite = 0, ocfra; + int add = 0, overwrite = 0; float temp[14]; if(writer->totelem == 0 || writer->cfra <= 0) return 0; if(cache->flag & PTCACHE_DISK_CACHE) { + int cfra = cache->endframe; + /* allways start from scratch on the first frame */ if(writer->cfra == cache->startframe) { BKE_ptcache_id_clear(writer->pid, PTCACHE_CLEAR_ALL, writer->cfra); @@ -616,7 +626,7 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer) add = 1; } else { - int cfra = cache->endframe; + int ocfra; /* find last cached frame */ while(cfra > cache->startframe && !BKE_ptcache_id_exist(writer->pid, cfra)) cfra--; @@ -626,7 +636,7 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer) while(ocfra > cache->startframe && !BKE_ptcache_id_exist(writer->pid, ocfra)) ocfra--; - if(writer->cfra > cfra) { + if(cfra >= cache->startframe && writer->cfra > cfra) { if(ocfra >= cache->startframe && cfra - ocfra < cache->step) overwrite = 1; else @@ -636,7 +646,7 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer) if(add || overwrite) { if(overwrite) - BKE_ptcache_id_clear(writer->pid, PTCACHE_CLEAR_FRAME, ocfra); + BKE_ptcache_id_clear(writer->pid, PTCACHE_CLEAR_FRAME, cfra); pf = BKE_ptcache_file_open(writer->pid, PTCACHE_FILE_WRITE, writer->cfra); if(!pf) @@ -665,7 +675,7 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer) pm2 = cache->mem_cache.last; if(pm2 && writer->cfra > pm2->frame) { - if(pm2 && pm2->prev && pm2->frame - pm2->prev->frame < cache->step) + if(pm2->prev && pm2->frame - pm2->prev->frame < cache->step) overwrite = 1; else add = 1; @@ -1102,6 +1112,10 @@ PointCache *BKE_ptcache_copy(PointCache *cache) ncache= MEM_dupallocN(cache); + /* hmm, should these be copied over instead? */ + ncache->mem_cache.first = NULL; + ncache->mem_cache.last = NULL; + ncache->flag= 0; ncache->simframe= 0; @@ -1211,8 +1225,9 @@ void BKE_ptcache_make_cache(PTCacheBaker* baker) cache = pid->cache; if((cache->flag & PTCACHE_BAKED)==0) { if(pid->type==PTCACHE_TYPE_PARTICLES) { - /* skip hair particles */ - if(((ParticleSystem*)pid->data)->part->type == PART_HAIR) + ParticleSystem *psys = (ParticleSystem*)pid->data; + /* skip hair & keyed particles */ + if(psys->part->type == PART_HAIR || psys->part->phystype == PART_PHYS_KEYED) continue; psys_get_pointcache_start_end(scene, pid->data, &cache->startframe, &cache->endframe); @@ -1310,6 +1325,7 @@ void BKE_ptcache_toggle_disk_cache(PTCacheID *pid) { if (!G.relbase_valid){ cache->flag &= ~PTCACHE_DISK_CACHE; + printf("File must be saved before using disk cache!\n"); return; } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 479fa760423..c2b19a804ee 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2968,6 +2968,9 @@ static void direct_link_pointcache(FileData *fd, PointCache *cache) for(; pm; pm=pm->next) pm->data = newdataadr(fd, pm->data); } + else + cache->mem_cache.first = cache->mem_cache.last = NULL; + cache->flag &= ~(PTCACHE_SIMULATION_VALID|PTCACHE_BAKE_EDIT_ACTIVE); cache->simframe= 0; } @@ -3011,12 +3014,18 @@ static void lib_link_particlesystems(FileData *fd, Object *ob, ID *id, ListBase psys->part = newlibadr_us(fd, id->lib, psys->part); if(psys->part) { + KeyedParticleTarget *kpt = psys->keyed_targets.first; + + for(; kpt; kpt=kpt->next) + kpt->ob=newlibadr(fd, id->lib, kpt->ob); + psys->target_ob = newlibadr(fd, id->lib, psys->target_ob); - psys->keyed_ob = newlibadr(fd, id->lib, psys->keyed_ob); for(a=0,pa=psys->particles; a<psys->totpart; a++,pa++){ pa->stick_ob=newlibadr(fd, id->lib, pa->stick_ob); } + + } else { /* particle modifier must be removed before particle system */ @@ -3066,6 +3075,8 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles) direct_link_pointcache(fd, sb->pointcache); } + link_list(fd, &psys->keyed_targets); + psys->edit = 0; psys->free_edit = NULL; psys->pathcache = 0; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 4b52da83019..65a4a355717 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -589,6 +589,7 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase) static void write_particlesystems(WriteData *wd, ListBase *particles) { ParticleSystem *psys= particles->first; + KeyedParticleTarget *kpt; int a; for(; psys; psys=psys->next) { @@ -604,6 +605,10 @@ static void write_particlesystems(WriteData *wd, ListBase *particles) writestruct(wd, DATA, "HairKey", pa->totkey, pa->hair); } } + kpt = psys->keyed_targets.first; + for(; kpt; kpt=kpt->next) + writestruct(wd, DATA, "KeyedParticleTarget", 1, kpt); + if(psys->child) writestruct(wd, DATA, "ChildParticle", psys->totchild ,psys->child); writestruct(wd, DATA, "SoftBody", 1, psys->soft); if(psys->soft) write_pointcaches(wd, psys->soft->pointcache, PTCACHE_WRITE_PSYS); diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h index 65c2976d57c..f16a232f26d 100644 --- a/source/blender/editors/space_buttons/buttons_intern.h +++ b/source/blender/editors/space_buttons/buttons_intern.h @@ -75,6 +75,10 @@ void OBJECT_OT_particle_system_add(struct wmOperatorType *ot); void OBJECT_OT_particle_system_remove(struct wmOperatorType *ot); void PARTICLE_OT_new(struct wmOperatorType *ot); +void PARTICLE_OT_new_keyed_target(struct wmOperatorType *ot); +void PARTICLE_OT_remove_keyed_target(struct wmOperatorType *ot); +void PARTICLE_OT_keyed_target_move_up(struct wmOperatorType *ot); +void PARTICLE_OT_keyed_target_move_down(struct wmOperatorType *ot); #endif /* ED_BUTTONS_INTERN_H */ diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index 66b380ab413..6fb52c61131 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -49,6 +49,7 @@ #include "BKE_world.h" #include "BLI_editVert.h" +#include "BLI_listbase.h" #include "RNA_access.h" @@ -473,33 +474,32 @@ static int new_particle_settings_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Main *bmain= CTX_data_main(C); - ParticleSettings *part= CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings).data; + ParticleSystem *psys; + ParticleSettings *part = NULL; Object *ob; PointerRNA ptr; + ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem); + + psys = ptr.data; + /* add or copy particle setting */ - if(part) - part= psys_copy_settings(part); + if(psys->part) + part= psys_copy_settings(psys->part); else part= psys_new_settings("PSys", bmain); - /* attempt to assign to material slot */ - ptr= CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem); + ob= ptr.id.data; - if(ptr.data) { - ParticleSystem *psys = (ParticleSystem*)ptr.data; - ob= ptr.id.data; - - if(psys->part) - psys->part->id.us--; + if(psys->part) + psys->part->id.us--; - psys->part = part; + psys->part = part; - DAG_scene_sort(scene); - DAG_object_flush_update(scene, ob, OB_RECALC_DATA); + DAG_scene_sort(scene); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); - } + WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); return OPERATOR_FINISHED; } @@ -517,3 +517,175 @@ void PARTICLE_OT_new(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } +/********************** keyed particle target operators *********************/ + +static int new_keyed_particle_target_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem); + ParticleSystem *psys= ptr.data; + Object *ob = ptr.id.data; + + KeyedParticleTarget *kpt; + + if(!psys) + return OPERATOR_CANCELLED; + + kpt = psys->keyed_targets.first; + for(; kpt; kpt=kpt->next) + kpt->flag &= ~KEYED_TARGET_CURRENT; + + kpt = MEM_callocN(sizeof(KeyedParticleTarget), "keyed particle target"); + + kpt->flag |= KEYED_TARGET_CURRENT; + kpt->psys = 1; + + BLI_addtail(&psys->keyed_targets, kpt); + + DAG_scene_sort(scene); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); + + WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + + return OPERATOR_FINISHED; +} + +void PARTICLE_OT_new_keyed_target(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "New Keyed Particle Target"; + ot->idname= "PARTICLE_OT_new_keyed_target"; + + /* api callbacks */ + ot->exec= new_keyed_particle_target_exec; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int remove_keyed_particle_target_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem); + ParticleSystem *psys= ptr.data; + Object *ob = ptr.id.data; + + KeyedParticleTarget *kpt; + + if(!psys) + return OPERATOR_CANCELLED; + + kpt = psys->keyed_targets.first; + for(; kpt; kpt=kpt->next) { + if(kpt->flag & KEYED_TARGET_CURRENT) { + BLI_remlink(&psys->keyed_targets, kpt); + MEM_freeN(kpt); + break; + } + + } + kpt = psys->keyed_targets.last; + + if(kpt) + kpt->flag |= KEYED_TARGET_CURRENT; + + DAG_scene_sort(scene); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); + + WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + + return OPERATOR_FINISHED; +} + +void PARTICLE_OT_remove_keyed_target(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Remove Keyed Particle Target"; + ot->idname= "PARTICLE_OT_remove_keyed_target"; + + /* api callbacks */ + ot->exec= remove_keyed_particle_target_exec; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/************************ move up modifier operator *********************/ + +static int keyed_target_move_up_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem); + ParticleSystem *psys= ptr.data; + Object *ob = ptr.id.data; + KeyedParticleTarget *kpt; + + if(!psys) + return OPERATOR_CANCELLED; + + kpt = psys->keyed_targets.first; + for(; kpt; kpt=kpt->next) { + if(kpt->flag & KEYED_TARGET_CURRENT && kpt->prev) { + BLI_remlink(&psys->keyed_targets, kpt); + BLI_insertlink(&psys->keyed_targets, kpt->prev->prev, kpt); + + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + break; + } + } + + return OPERATOR_FINISHED; +} + +void PARTICLE_OT_keyed_target_move_up(wmOperatorType *ot) +{ + ot->name= "Move Up Keyed Target"; + ot->description= "Move keyed particle target up in the list."; + ot->idname= "PARTICLE_OT_keyed_target_move_up"; + + ot->exec= keyed_target_move_up_exec; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/************************ move down modifier operator *********************/ + +static int keyed_target_move_down_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem); + ParticleSystem *psys= ptr.data; + Object *ob = ptr.id.data; + KeyedParticleTarget *kpt; + + if(!psys) + return OPERATOR_CANCELLED; + kpt = psys->keyed_targets.first; + for(; kpt; kpt=kpt->next) { + if(kpt->flag & KEYED_TARGET_CURRENT && kpt->next) { + BLI_remlink(&psys->keyed_targets, kpt); + BLI_insertlink(&psys->keyed_targets, kpt->next, kpt); + + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + break; + } + } + + return OPERATOR_FINISHED; +} + +void PARTICLE_OT_keyed_target_move_down(wmOperatorType *ot) +{ + ot->name= "Move Down Keyed Target"; + ot->description= "Move keyed particle target down in the list."; + ot->idname= "PARTICLE_OT_keyed_target_move_down"; + + ot->exec= keyed_target_move_down_exec; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index f7be323a4c5..6cdb4dbf93d 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -224,6 +224,10 @@ void buttons_operatortypes(void) WM_operatortype_append(OBJECT_OT_particle_system_remove); WM_operatortype_append(PARTICLE_OT_new); + WM_operatortype_append(PARTICLE_OT_new_keyed_target); + WM_operatortype_append(PARTICLE_OT_remove_keyed_target); + WM_operatortype_append(PARTICLE_OT_keyed_target_move_up); + WM_operatortype_append(PARTICLE_OT_keyed_target_move_down); } void buttons_keymap(struct wmWindowManager *wm) diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index e8749537f5e..f83a0b9686e 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -3161,15 +3161,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv /* 2. */ if(part->phystype==PART_PHYS_KEYED){ - if(psys->flag & PSYS_FIRST_KEYED){ - if(psys->flag&PSYS_KEYED){ - select=psys_count_keyed_targets(ob,psys); - if(psys->totkeyed==0) - return; - } + if(psys->flag&PSYS_KEYED){ + psys_count_keyed_targets(ob,psys); + if(psys->totkeyed==0) + return; } - else - return; } if(select){ @@ -3226,8 +3222,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv else draw_as = part->draw_as; - if(part->flag&PART_GLOB_TIME) - cfra=bsystem_time(scene, 0, (float)CFRA, 0.0f); + //if(part->flag&PART_GLOB_TIME) + cfra=bsystem_time(scene, 0, (float)CFRA, 0.0f); if(draw_as==PART_DRAW_PATH && psys->pathcache==NULL) draw_as=PART_DRAW_DOT; @@ -3306,8 +3302,10 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv if(draw_as && draw_as!=PART_DRAW_PATH) { int tot_vec_size = (totpart + totchild) * 3 * sizeof(float); - if(part->draw_as == PART_DRAW_REND && part->trail_count > 1) + if(part->draw_as == PART_DRAW_REND && part->trail_count > 1) { tot_vec_size *= part->trail_count; + psys_make_temp_pointcache(ob, psys); + } if(draw_as!=PART_DRAW_CIRC) { switch(draw_as) { @@ -3361,8 +3359,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv pa_dietime = pa->dietime; pa_size=pa->size; - if((part->flag&PART_ABS_TIME)==0){ -#if 0 // XXX old animation system +#if 0 // XXX old animation system + if((part->flag&PART_ABS_TIME)==0){ if(ma && ma->ipo){ IpoCurve *icu; @@ -3389,8 +3387,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv pa_size = icu->curval; } } -#endif // XXX old animation system } +#endif // XXX old animation system r_tilt = 1.0f + pa->r_ave[0]; r_length = 0.5f * (1.0f + pa->r_ave[1]); @@ -3400,9 +3398,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv pa_time=psys_get_child_time(psys,cpa,cfra,&pa_birthtime,&pa_dietime); +#if 0 // XXX old animation system if((part->flag&PART_ABS_TIME)==0) { if(ma && ma->ipo){ -#if 0 // XXX old animation system IpoCurve *icu; /* correction for lifetime */ @@ -3416,9 +3414,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv else if(icu->adrcode == MA_COL_B) ma_b = icu->curval; } -#endif // XXX old animation system } } +#endif // XXX old animation system pa_size=psys_get_child_size(psys,cpa,cfra,0); @@ -3444,7 +3442,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv else if(ct < 0.0f || ct > 1.0f) continue; - state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : ct; + state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : -(pa_birthtime + ct * (pa_dietime - pa_birthtime)); psys_get_particle_on_path(scene,ob,psys,a,&state,need_v); if(psys->parent) diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index c793362c223..0b3309bfc0c 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -61,6 +61,14 @@ typedef struct ChildParticle { float rand[3]; } ChildParticle; +typedef struct KeyedParticleTarget { + struct KeyedParticleTarget *next, *prev; + struct Object *ob; + int psys; + short flag, rt; + float time, duration; +} KeyedParticleTarget; + /* Everything that's non dynamic for a particle: */ typedef struct ParticleData { struct Object *stick_ob;/* object that particle sticks to when dead */ @@ -131,7 +139,7 @@ typedef struct ParticleSettings { /* general values */ float sta, end, lifetime, randlife; - float timetweak, jitfac, keyed_time, eff_hair; + float timetweak, jitfac, eff_hair; int totpart, userjit, grid_res; /* initial velocity factors */ @@ -142,11 +150,11 @@ typedef struct ParticleSettings { /* global physical properties */ float acc[3], dragfac, brownfac, dampfac; /* length */ - float length, abslength, randlength; + float randlength; /* children */ int child_nbr, ren_child_nbr; float parents, childsize, childrandsize; - float childrad, childflat, childspread; + float childrad, childflat, rt; /* clumping */ float clumpfac, clumppow; /* kink */ @@ -155,12 +163,16 @@ typedef struct ParticleSettings { float rough1, rough1_size; float rough2, rough2_size, rough2_thres; float rough_end, rough_end_shape; + /* length */ + float clength, clength_thres; /* branching */ float branch_thres; /* drawing stuff */ float draw_line[2]; float path_start, path_end; int trail_count; + /* keyed particles */ + int keyed_loops; /* boids */ float max_vel, max_lat_acc, max_tan_acc; @@ -195,17 +207,18 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in struct SoftBody *soft; /* hair softbody */ struct Object *target_ob; - struct Object *keyed_ob; struct Object *lattice; struct Object *parent; /* particles from global space -> parent space */ struct ListBase effectors, reactevents; /* runtime */ + + struct ListBase keyed_targets; float imat[4][4]; /* used for duplicators */ float cfra; int seed; int flag, totpart, totchild, totcached, totchildcache, rt; - short recalc, target_psys, keyed_psys, totkeyed, softflag, bakespace; + short recalc, target_psys, totkeyed, softflag, bakespace, rt2; char bb_uvname[3][32]; /* billboard uv name */ @@ -255,10 +268,10 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in #define PART_ROT_DYN (1<<14) /* dynamic rotation */ #define PART_SIZEMASS (1<<16) -#define PART_ABS_LENGTH (1<<15) +//#define PART_KEYED_TIMING (1<<15) -#define PART_ABS_TIME (1<<17) -#define PART_GLOB_TIME (1<<18) +//#define PART_ABS_TIME (1<<17) +//#define PART_GLOB_TIME (1<<18) #define PART_BOIDS_2D (1<<19) @@ -396,14 +409,15 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in #define PSYS_RECALC_RESET 2 /* reset everything including pointcache */ #define PSYS_RECALC_TYPE 4 /* handle system type change */ #define PSYS_RECALC_CHILD 16 /* only child settings changed */ +#define PSYS_RECALC_PHYS 32 /* physics type changed */ /* psys->flag */ #define PSYS_CURRENT 1 //#define PSYS_BAKING 2 //#define PSYS_BAKE_UI 4 -#define PSYS_KEYED_TIME 8 +#define PSYS_KEYED_TIMING 8 #define PSYS_ENABLED 16 /* deprecated */ -#define PSYS_FIRST_KEYED 32 +//#define PSYS_FIRST_KEYED 32 #define PSYS_DRAWING 64 //#define PSYS_SOFT_BAKE 128 #define PSYS_DELETE 256 /* remove particlesystem as soon as possible */ @@ -458,6 +472,10 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in #define BOID_GOAL 6 #define BOID_LEVEL 7 +/* psys->keyed_targets->flag */ +#define KEYED_TARGET_CURRENT 1 +#define KEYED_TARGET_VALID 2 + //#define PSYS_INTER_CUBIC 0 //#define PSYS_INTER_LINEAR 1 diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 3631d83310a..ed1a8052acd 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -221,6 +221,7 @@ extern StructRNA RNA_Key; extern StructRNA RNA_KeyboardSensor; extern StructRNA RNA_KeyingSet; extern StructRNA RNA_KeyingSetPath; +extern StructRNA RNA_KeyedParticleTarget; extern StructRNA RNA_KinematicConstraint; extern StructRNA RNA_Lamp; extern StructRNA RNA_LampSkySettings; diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 98ed12afd5a..39411752792 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -140,6 +140,35 @@ static void rna_Particle_reset(bContext *C, PointerRNA *ptr) } } +static void rna_Particle_keyed_reset(bContext *C, PointerRNA *ptr) +{ + Scene *scene = CTX_data_scene(C); + + if(ptr->type==&RNA_KeyedParticleTarget) { + Object *ob = (Object*)ptr->id.data; + ParticleSystem *psys = psys_get_current(ob); + + psys->recalc = PSYS_RECALC_RESET; + + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); + DAG_scene_sort(scene); + } +} + +static void rna_Particle_keyed_redo(bContext *C, PointerRNA *ptr) +{ + Scene *scene = CTX_data_scene(C); + + if(ptr->type==&RNA_KeyedParticleTarget) { + Object *ob = (Object*)ptr->id.data; + ParticleSystem *psys = psys_get_current(ob); + + psys->recalc = PSYS_RECALC_REDO; + + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); + } +} + static void rna_Particle_change_type(bContext *C, PointerRNA *ptr) { Scene *scene = CTX_data_scene(C); @@ -161,6 +190,13 @@ static void rna_Particle_change_type(bContext *C, PointerRNA *ptr) } } +static void rna_Particle_change_physics(bContext *C, PointerRNA *ptr) +{ + Scene *scene = CTX_data_scene(C); + ParticleSettings *part = ptr->id.data; + psys_flush_particle_settings(scene, part, PSYS_RECALC_RESET|PSYS_RECALC_PHYS); +} + static void rna_Particle_redo_child(bContext *C, PointerRNA *ptr) { Scene *scene = CTX_data_scene(C); @@ -299,6 +335,97 @@ static void rna_ParticleSystem_name_get(PointerRNA *ptr, char *str) strcpy(str, ""); } +static PointerRNA rna_ParticleSystem_active_keyed_target_get(PointerRNA *ptr) +{ + ParticleSystem *psys= (ParticleSystem*)ptr->data; + KeyedParticleTarget *kpt = psys->keyed_targets.first; + + for(; kpt; kpt=kpt->next) { + if(kpt->flag & KEYED_TARGET_CURRENT) + return rna_pointer_inherit_refine(ptr, &RNA_KeyedParticleTarget, kpt); + } + return rna_pointer_inherit_refine(ptr, &RNA_KeyedParticleTarget, NULL); +} +static void rna_ParticleSystem_active_keyed_target_index_range(PointerRNA *ptr, int *min, int *max) +{ + ParticleSystem *psys= (ParticleSystem*)ptr->data; + *min= 0; + *max= BLI_countlist(&psys->keyed_targets)-1; + *max= MAX2(0, *max); +} + +static int rna_ParticleSystem_active_keyed_target_index_get(PointerRNA *ptr) +{ + ParticleSystem *psys= (ParticleSystem*)ptr->data; + KeyedParticleTarget *kpt = psys->keyed_targets.first; + int i=0; + + for(; kpt; kpt=kpt->next, i++) + if(kpt->flag & KEYED_TARGET_CURRENT) + return i; + + return 0; +} + +static void rna_ParticleSystem_active_keyed_target_index_set(struct PointerRNA *ptr, int value) +{ + ParticleSystem *psys= (ParticleSystem*)ptr->data; + KeyedParticleTarget *kpt = psys->keyed_targets.first; + int i=0; + + for(; kpt; kpt=kpt->next, i++) { + if(i==value) + kpt->flag |= KEYED_TARGET_CURRENT; + else + kpt->flag &= ~KEYED_TARGET_CURRENT; + } +} +static int rna_KeyedParticleTarget_name_length(PointerRNA *ptr) +{ + KeyedParticleTarget *kpt= ptr->data; + + if(kpt->flag & KEYED_TARGET_VALID) { + if(kpt->ob) + return strlen(kpt->ob->id.name+2) + 4; + else + return 20; + } + else + return 15; + + return 0; +} + +static void rna_KeyedParticleTarget_name_get(PointerRNA *ptr, char *str) +{ + KeyedParticleTarget *kpt= ptr->data; + + if(kpt->flag & KEYED_TARGET_VALID) { + if(kpt->ob) + sprintf(str, "%s: %i", kpt->ob->id.name+2, kpt->psys); + else + sprintf(str, "Particle System: %i", kpt->psys); + + } + else + strcpy(str, "Invalid target!"); +} + +static EnumPropertyItem from_items[] = { + {PART_FROM_VERT, "VERT", 0, "Vertexes", ""}, + {PART_FROM_FACE, "FACE", 0, "Faces", ""}, + {PART_FROM_VOLUME, "VOLUME", 0, "Volume", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem reactor_from_items[] = { + {PART_FROM_VERT, "VERT", 0, "Vertexes", ""}, + {PART_FROM_FACE, "FACE", 0, "Faces", ""}, + {PART_FROM_VOLUME, "VOLUME", 0, "Volume", ""}, + {PART_FROM_PARTICLE, "PARTICLE", 0, "Particle", ""}, + {0, NULL, 0, NULL, NULL} +}; + static EnumPropertyItem *rna_Particle_from_itemf(bContext *C, PointerRNA *ptr, int *free) { ParticleSettings *part = ptr->id.data; @@ -660,16 +787,19 @@ static void rna_def_particle_settings(BlenderRNA *brna) /* flag */ prop= RNA_def_property(srna, "react_start_end", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_REACT_STA_END); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_ui_text(prop, "Start/End", "Give birth to unreacted particles eventually."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "react_multiple", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_REACT_MULTIPLE); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_ui_text(prop, "Multi React", "React multiple times."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "loop", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_LOOP); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_ui_text(prop, "Loop", "Loop particle lives."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); @@ -690,54 +820,46 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop= RNA_def_property(srna, "trand", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_TRAND); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_ui_text(prop, "Random", "Emit in random order of elements"); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "even_distribution", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_EDISTR); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_ui_text(prop, "Even Distribution", "Use even distribution from faces based on face areas or edge lengths."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "sticky", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_STICKY); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_ui_text(prop, "Sticky", "Particles stick to collided objects if they die in the collision."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "die_on_collision", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_DIE_ON_COL); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_ui_text(prop, "Die on hit", "Particles die when they collide with a deflector object."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "size_deflect", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_SIZE_DEFL); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_ui_text(prop, "Size Deflect", "Use particle's size in deflection."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "rotation_dynamic", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_ROT_DYN); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_ui_text(prop, "Dynamic", "Sets rotation to dynamic/constant"); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "sizemass", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_SIZEMASS); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_ui_text(prop, "Mass from Size", "Multiply mass with particle size."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); - prop= RNA_def_property(srna, "abs_length", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_ABS_LENGTH); - RNA_def_property_ui_text(prop, "Abs Length", "Use maximum length for children"); - RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); - - //prop= RNA_def_property(srna, "absolute_time", PROP_BOOLEAN, PROP_NONE); - //RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_ABS_TIME); - //RNA_def_property_ui_text(prop, "Absolute Time", "Set all ipos that work on particles to be calculated in absolute/relative time."); - //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); - - //prop= RNA_def_property(srna, "global_time", PROP_BOOLEAN, PROP_NONE); - //RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_GLOB_TIME); - //RNA_def_property_ui_text(prop, "Global Time", "Set all ipos that work on particles to be calculated in global/object time."); - //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); - prop= RNA_def_property(srna, "boids_2d", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_BOIDS_2D); RNA_def_property_ui_text(prop, "Boids 2D", "Constrain boids to a surface"); @@ -796,18 +918,21 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, type_items); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_ui_text(prop, "Type", ""); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_change_type"); prop= RNA_def_property(srna, "emit_from", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "from"); RNA_def_property_enum_items(prop, part_reactor_from_items); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Particle_from_itemf"); RNA_def_property_ui_text(prop, "Emit From", "Where to emit particles from"); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "distr"); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_enum_items(prop, dist_items); RNA_def_property_ui_text(prop, "Distribution", "How to distribute particles on selected element"); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); @@ -815,24 +940,28 @@ static void rna_def_particle_settings(BlenderRNA *brna) /* physics modes */ prop= RNA_def_property(srna, "physics_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "phystype"); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_enum_items(prop, phys_type_items); RNA_def_property_ui_text(prop, "Physics Type", "Particle physics type"); - RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); + RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_change_physics"); prop= RNA_def_property(srna, "rotation_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "rotmode"); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_enum_items(prop, rot_mode_items); RNA_def_property_ui_text(prop, "Rotation", "Particles initial rotation"); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "angular_velocity_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "avemode"); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_enum_items(prop, ave_mode_items); RNA_def_property_ui_text(prop, "Angular Velocity Mode", "Particle angular velocity mode."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "react_event", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "reactevent"); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_enum_items(prop, react_event_items); RNA_def_property_ui_text(prop, "React On", "The event of target particles to react on."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); @@ -843,11 +972,6 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Velocity", "Show particle velocity"); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); - //prop= RNA_def_property(srna, "draw_path_length", PROP_BOOLEAN, PROP_NONE); - //RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_PATH_LEN); - //RNA_def_property_ui_text(prop, "Path length", "Draw path length"); - //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); - prop= RNA_def_property(srna, "show_size", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_SIZE); RNA_def_property_ui_text(prop, "Size", "Show particle size"); @@ -936,7 +1060,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "childtype"); RNA_def_property_enum_items(prop, child_type_items); RNA_def_property_ui_text(prop, "Children From", "Create child particles"); - RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); + RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo_child"); prop= RNA_def_property(srna, "draw_step", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 0, 7); @@ -1091,12 +1215,15 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop= RNA_def_property(srna, "start", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "sta");//optional if prop names are the same RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_float_funcs(prop, NULL, "rna_PartSettings_start_set", NULL); RNA_def_property_ui_text(prop, "Start", "Frame # to start emitting particles."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "end", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF); + + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_float_funcs(prop, NULL, "rna_PartSettings_end_set", NULL); RNA_def_property_ui_text(prop, "End", "Frame # to stop emitting particles."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); @@ -1119,38 +1246,35 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "jitter_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_float_sdna(prop, NULL, "jitfac"); RNA_def_property_range(prop, 0.0f, 2.0f); RNA_def_property_ui_text(prop, "Amount", "Amount of jitter applied to the sampling."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); - prop= RNA_def_property(srna, "keyed_time", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Time", "Keyed key time relative to remaining particle life."); - RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); - prop= RNA_def_property(srna, "effect_hair", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "eff_hair"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Stiffnes", "Hair stiffness for effectors"); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); - //float rt; TODO:find where rt is used - can't find it in UI - prop= RNA_def_property(srna, "amount", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "totpart"); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_range(prop, 0, 100000); RNA_def_property_ui_text(prop, "Amount", "Total number of particles."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "userjit", PROP_INT, PROP_UNSIGNED);//TODO: can we get a better name for userjit? RNA_def_property_int_sdna(prop, NULL, "userjit"); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_range(prop, 0, 1000); RNA_def_property_ui_text(prop, "P/F", "Emission locations / face (0 = automatic)."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); prop= RNA_def_property(srna, "grid_resolution", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "grid_res"); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); RNA_def_property_range(prop, 1, 100); RNA_def_property_ui_text(prop, "Resolution", "The resolution of the particle grid."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); @@ -1273,19 +1397,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Damp", "Specify the amount of damping"); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); - /* length */ - //TODO: is this readonly? - prop= RNA_def_property(srna, "length", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "length"); -// RNA_def_property_range(prop, 0.0f, upperLimitf);//TODO: limits - RNA_def_property_ui_text(prop, "Length", ""); - - prop= RNA_def_property(srna, "absolute_length", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "abslength"); - RNA_def_property_range(prop, 0.0f, 10000.0f); - RNA_def_property_ui_text(prop, "Max Length", "Absolute maximum path length for children, in blender units."); - RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); - + /* random length */ prop= RNA_def_property(srna, "random_length", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "randlength"); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -1334,13 +1446,6 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Child Roundness", "Roundness of children around parent."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo_child"); - //TODO: is this readonly? - prop= RNA_def_property(srna, "child_spread", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "childspread"); -// RNA_def_property_range(prop, 0.0f, upperLimitf); TODO: limits - RNA_def_property_ui_text(prop, "Child Spread", ""); - RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo_child"); - /* clumping */ prop= RNA_def_property(srna, "clump_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "clumpfac"); @@ -1414,6 +1519,18 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Shape", "Shape of end point rough"); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo_child"); + prop= RNA_def_property(srna, "child_length", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "clength"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Length", "Length of child paths"); + RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo_child"); + + prop= RNA_def_property(srna, "child_length_thres", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "clength_thres"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Threshold", "Amount of particles left untouched by child path length."); + RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo_child"); + /* branching */ prop= RNA_def_property(srna, "branch_threshold", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "branch_thres"); @@ -1451,7 +1568,14 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_range(prop, 1.0f, 100.0f); RNA_def_property_ui_text(prop, "Trail Count", "Number of trail particles."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); - + + /* keyed particles */ + prop= RNA_def_property(srna, "keyed_loops", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "keyed_loops"); + RNA_def_property_range(prop, 1.0f, 100.0f); + RNA_def_property_ui_text(prop, "Loop count", "Number of times the keys are looped."); + RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); + /* boids */ prop= RNA_def_property(srna, "max_velocity", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "max_vel"); @@ -1494,14 +1618,6 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Ground Z", "Default Z value"); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); - /*TODO: not sure how to deal with this - prop= RNA_def_property(srna, "boid_factor", PROP_FLOAT, PROP_VECTOR); - RNA_def_property_float_sdna(prop, NULL, "boidfac"); - RNA_def_property_ui_text(prop, "Boid Factor", ""); - - //char boidrule[8]; - */ - prop= RNA_def_property(srna, "dupli_group", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "dup_group"); RNA_def_property_struct_type(prop, "Group"); @@ -1537,6 +1653,52 @@ static void rna_def_particle_settings(BlenderRNA *brna) // struct PartDeflect *pd2; } +static void rna_def_keyed_particle_target(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "KeyedParticleTarget", NULL); + RNA_def_struct_ui_text(srna, "Keyed Particle Target", "Target particle system for keyed particles."); + + prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, "rna_KeyedParticleTarget_name_get", "rna_KeyedParticleTarget_name_length", NULL); + RNA_def_property_ui_text(prop, "Name", "Keyed particle target name."); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_struct_name_property(srna, prop); + + prop= RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "ob"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Target Object", "The object that has the target particle system (empty if same object)."); + RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_keyed_reset"); + + prop= RNA_def_property(srna, "system", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "psys"); + RNA_def_property_range(prop, 1, INT_MAX); + RNA_def_property_ui_text(prop, "Target Particle System", "The index of particle system on the target object."); + RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_keyed_reset"); + + prop= RNA_def_property(srna, "time", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "time"); + RNA_def_property_range(prop, 0.0, 30000.0f); //TODO: replace 30000 with MAXFRAMEF when available in 2.5 + RNA_def_property_ui_text(prop, "Time", ""); + RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_keyed_redo"); + + prop= RNA_def_property(srna, "duration", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "duration"); + RNA_def_property_range(prop, 0.0, 30000.0f); //TODO: replace 30000 with MAXFRAMEF when available in 2.5 + RNA_def_property_ui_text(prop, "Duration", ""); + RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_keyed_redo"); + + prop= RNA_def_property(srna, "valid", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYED_TARGET_VALID); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); + RNA_def_property_ui_text(prop, "Valid", "Keyed particles target is valid."); + + + +} static void rna_def_particle_system(BlenderRNA *brna) { StructRNA *srna; @@ -1604,34 +1766,33 @@ static void rna_def_particle_system(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); /* boids */ - prop= RNA_def_property(srna, "boids_surface_object", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "keyed_ob"); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Boids Surface Object", "For boids physics systems, constrain boids to this object's surface."); - RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); + //prop= RNA_def_property(srna, "boids_surface_object", PROP_POINTER, PROP_NONE); + //RNA_def_property_pointer_sdna(prop, NULL, "keyed_ob"); + //RNA_def_property_flag(prop, PROP_EDITABLE); + //RNA_def_property_ui_text(prop, "Boids Surface Object", "For boids physics systems, constrain boids to this object's surface."); + //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); /* keyed */ - prop= RNA_def_property(srna, "keyed_object", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "keyed_ob"); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Keyed Object", "For keyed physics systems, the object that has the target particle system."); - RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); + prop= RNA_def_property(srna, "keyed_timing", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_KEYED_TIMING); + RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE); + RNA_def_property_ui_text(prop, "Keyed timing", "Use key times"); + RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); - prop= RNA_def_property(srna, "keyed_particle_system", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "keyed_psys"); - RNA_def_property_range(prop, 1, INT_MAX); - RNA_def_property_ui_text(prop, "Keyed Particle System", "For keyed physics systems, index of particle system on the keyed object."); - RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); + prop= RNA_def_property(srna, "keyed_targets", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "keyed_targets", NULL); + RNA_def_property_struct_type(prop, "KeyedParticleTarget"); + RNA_def_property_ui_text(prop, "Keyed Targets", "Target particle systems for keyed particles"); - prop= RNA_def_property(srna, "keyed_first", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_FIRST_KEYED); - RNA_def_property_ui_text(prop, "Keyed First", "Set the system to be the starting point of keyed particles"); - RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); + prop= RNA_def_property(srna, "active_keyed_target", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "KeyedParticleTarget"); + RNA_def_property_pointer_funcs(prop, "rna_ParticleSystem_active_keyed_target_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Active Particle System", "Active particle system being displayed"); + + prop= RNA_def_property(srna, "active_keyed_target_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_funcs(prop, "rna_ParticleSystem_active_keyed_target_index_get", "rna_ParticleSystem_active_keyed_target_index_set", "rna_ParticleSystem_active_keyed_target_index_range"); + RNA_def_property_ui_text(prop, "Active Particle System Index", "Index of active particle system slot."); - prop= RNA_def_property(srna, "keyed_timed", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_KEYED_TIME); - RNA_def_property_ui_text(prop, "Keyed Timed", "Use intermediate key times for keyed particles (setting for starting point only)."); - RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset"); /* billboard */ prop= RNA_def_property(srna, "billboard_normal_uv", PROP_STRING, PROP_NONE); @@ -1782,7 +1943,6 @@ static void rna_def_particle_system(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Parent", "Use this object's coordinate system instead of global coordinate system."); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); - } void RNA_def_particle(BlenderRNA *brna) @@ -1791,6 +1951,7 @@ void RNA_def_particle(BlenderRNA *brna) rna_def_particle_key(brna); rna_def_child_particle(brna); rna_def_particle(brna); + rna_def_keyed_particle_target(brna); rna_def_particle_system(brna); rna_def_particle_settings(brna); } diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 74686511b21..1d6d98bebdf 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1513,12 +1513,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem return 1; /* 2. start initialising things */ - if(part->phystype==PART_PHYS_KEYED){ - if(psys->flag & PSYS_FIRST_KEYED) - psys_count_keyed_targets(ob,psys); - else - return 1; - } + if(part->phystype==PART_PHYS_KEYED) + psys_count_keyed_targets(ob,psys); /* last possibility to bail out! */ psmd= psys_get_modifier(ob,psys); @@ -1606,10 +1602,10 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem calc_ipo(part->ipo, cfra); execute_ipo((ID *)part, part->ipo); } -#endif // XXX old animation system if(part->flag & PART_GLOB_TIME) - cfra = bsystem_time(re->scene, 0, (float)re->scene->r.cfra, 0.0); +#endif // XXX old animation system + cfra = bsystem_time(re->scene, 0, (float)re->scene->r.cfra, 0.0); /* 2.4 setup reactors */ if(part->type == PART_REACTOR){ @@ -1707,8 +1703,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem pa_time=(cfra-pa->time)/pa->lifetime; pa_birthtime = pa->time; pa_dietime = pa->dietime; - if((part->flag&PART_ABS_TIME) == 0){ #if 0 // XXX old animation system + if((part->flag&PART_ABS_TIME) == 0){ if(ma->ipo) { /* correction for lifetime */ calc_ipo(ma->ipo, 100.0f * pa_time); @@ -1719,8 +1715,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem calc_ipo(part->ipo, 100.0f*pa_time); execute_ipo((ID *)part, part->ipo); } -#endif // XXX old animation system } +#endif // XXX old animation system hasize = ma->hasize; @@ -1767,8 +1763,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime); - if((part->flag & PART_ABS_TIME) == 0) { #if 0 // XXX old animation system + if((part->flag & PART_ABS_TIME) == 0) { if(ma->ipo){ /* correction for lifetime */ calc_ipo(ma->ipo, 100.0f * pa_time); @@ -1779,8 +1775,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem calc_ipo(part->ipo, 100.0f * pa_time); execute_ipo((ID *)part, part->ipo); } -#endif // XXX old animation system } +#endif // XXX old animation system pa_size = psys_get_child_size(psys, cpa, cfra, &pa_time); |