From 66918b3add4dfc90a8074f4bdc1c797ae9bf1371 Mon Sep 17 00:00:00 2001 From: Janne Karhu Date: Sat, 4 Jul 2009 03:50:12 +0000 Subject: [PATCH] A bunch of fun stuff now possible because of new pointcache code: * Baked normal particles can now use the "Path" visualization. * Path "max length" & "abs length" are now history: - New option to set path start & end times + random variation to length. - Much more flexible (and calculated better) than previous options. - This works with parents, children, hair & normal particles unlike old length option. - Only known issue for now is that children from faces don't get calculated correctly when using path start time. * New option "trails" for "halo", "line" and "billboard" visualizations: - Draws user controllable number of particle instances along particles path backwards from current position. - Works with children too for cool/weird visualizations that weren't possible before. * Normal particle children's velocities are now approximated better when needed so that "line" visualization trails will look nice. * New particle instance modifier options: - "path"-option works better and has controllable (max)position along path (with random variation possible). - "keep shape"-option for hair, keyed, or baked particles allows to place the instances to a single point (with random variation possible) along particle path. - "axis" option to make rotation handling better (still not perfect, but will have to do for now). Some fixes & cleanup done along the way: * Random path length didn't work for non-child particles. * Cached & unborn particles weren't reset to emit locations. * Particle numbers weren't drawn in the correct place. * Setting proper render & draw visualizations was lost somewhere when initializing new particle settings. * Changing child mode wasn't working correctly. * Some cleanup & modularization of particle child effector code and particle drawing & rendering code. * Object & group visualizations didn't work. * Child simplification didn't work. --- release/ui/buttons_data_modifier.py | 9 + release/ui/buttons_particle.py | 35 +- source/blender/blenkernel/BKE_particle.h | 5 +- source/blender/blenkernel/intern/anim.c | 13 +- source/blender/blenkernel/intern/depsgraph.c | 4 +- source/blender/blenkernel/intern/modifier.c | 60 +- source/blender/blenkernel/intern/particle.c | 535 +++++++++-------- .../blenkernel/intern/particle_system.c | 36 +- source/blender/blenkernel/intern/pointcache.c | 15 +- source/blender/blenloader/intern/readfile.c | 1 + .../editors/interface/interface_templates.c | 2 +- .../blender/editors/object/object_modifier.c | 4 +- .../blender/editors/space_view3d/drawobject.c | 543 ++++++++++++------ source/blender/makesdna/DNA_modifier_types.h | 4 +- source/blender/makesdna/DNA_particle_types.h | 8 +- source/blender/makesrna/intern/rna_modifier.c | 30 + source/blender/makesrna/intern/rna_particle.c | 73 ++- .../render/intern/source/convertblender.c | 161 ++++-- 18 files changed, 974 insertions(+), 564 deletions(-) diff --git a/release/ui/buttons_data_modifier.py b/release/ui/buttons_data_modifier.py index 2400461b623..477be27e820 100644 --- a/release/ui/buttons_data_modifier.py +++ b/release/ui/buttons_data_modifier.py @@ -300,9 +300,18 @@ class DATA_PT_modifiers(DataButtonsPanel): col.itemR(md, "normal") col.itemR(md, "children") col.itemR(md, "path") + if md.path: + col.itemR(md, "keep_shape") col.itemR(md, "unborn") col.itemR(md, "alive") col.itemR(md, "dead") + if md.path: + col.itemR(md, "axis", text="") + + if md.path: + row = layout.row() + row.itemR(md, "position", slider=True) + row.itemR(md, "random_position", text = "Random", slider=True) def particlesystem(self, layout, ob, md): layout.itemL(text="See Particle panel.") diff --git a/release/ui/buttons_particle.py b/release/ui/buttons_particle.py index 49ceaf6aae1..93ce9c5c745 100644 --- a/release/ui/buttons_particle.py +++ b/release/ui/buttons_particle.py @@ -353,19 +353,14 @@ class PARTICLE_PT_render(ParticleButtonsPanel): colsub.itemR(part, "adaptive_pix") sub.itemR(part, "hair_bspline") sub.itemR(part, "render_step", text="Steps") - sub = split.column() - sub.itemL(text="Length:") - sub.itemR(part, "abs_length", text="Absolute") - sub.itemR(part, "absolute_length", text="Maximum") + sub = split.column() + + sub.itemL(text="Timing:") + sub.itemR(part, "abs_path_time") + sub.itemR(part, "path_start", text="Start", slider= not part.abs_path_time) + sub.itemR(part, "path_end", text="End", slider= not part.abs_path_time) sub.itemR(part, "random_length", text="Random", slider=True) - #row = layout.row() - #row.itemR(part, "timed_path") - #col = row.column(align=True) - #col.active = part.timed_path == True - #col.itemR(part, "line_length_tail", text="Start") - #col.itemR(part, "line_length_head", text="End") - row = layout.row() col = row.column() @@ -384,7 +379,6 @@ class PARTICLE_PT_render(ParticleButtonsPanel): elif part.ren_as == 'OBJECT': - #sub = split.column() sub.itemR(part, "dupli_object") elif part.ren_as == 'GROUP': sub.itemR(part, "dupli_group") @@ -428,7 +422,19 @@ class PARTICLE_PT_render(ParticleButtonsPanel): row.itemR(part, "billboard_animation", expand=True) row.itemL(text="Offset:") row.itemR(part, "billboard_split_offset", expand=True) - + if part.ren_as == 'HALO' or part.ren_as == 'LINE' or part.ren_as=='BILLBOARD': + row = layout.row() + col = row.column() + col.itemR(part, "trail_count") + if part.trail_count > 1: + col.itemR(part, "abs_path_time", text="Length in frames") + col = row.column() + col.itemR(part, "path_end", text="Length", slider=not part.abs_path_time) + col.itemR(part, "random_length", text="Random", slider=True) + else: + col = row.column() + col.itemL(text="") + class PARTICLE_PT_draw(ParticleButtonsPanel): __idname__= "PARTICLE_PT_draw" __label__ = "Display" @@ -475,11 +481,12 @@ class PARTICLE_PT_draw(ParticleButtonsPanel): col.itemR(part, "draw_health") col = row.column() + col.itemR(part, "material_color", text="Use material color") + if (path): box = col.box() box.itemR(part, "draw_step") else: - col.itemR(part, "material_color", text="Use material color") subcol = col.column() subcol.active = part.material_color==False #subcol.itemL(text="color") diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 73f0195d1d8..aa24706077d 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -91,7 +91,8 @@ typedef struct ParticleTexture{ float ivel; /* used in reset */ float time, life, exist, size; /* used in init */ float pvel[3]; /* used in physics */ - float length, clump, kink, rough; /* used in path caching */ + float length, clump, kink, effector;/* used in path caching */ + float rough1, rough2, roughe; /* used in path caching */ } ParticleTexture; typedef struct BoidVecFunc{ @@ -270,7 +271,7 @@ void psys_update_world_cos(struct Object *ob, struct ParticleSystem *psys); int do_guide(struct Scene *scene, struct ParticleKey *state, int pa_num, float time, struct ListBase *lb); float psys_get_size(struct Object *ob, struct Material *ma, struct ParticleSystemModifierData *psmd, struct IpoCurve *icu_size, struct ParticleSystem *psys, struct ParticleSettings *part, struct ParticleData *pa, float *vg_size); float psys_get_timestep(struct ParticleSettings *part); -float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra); +float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *birthtime, float *dietime); float psys_get_child_size(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *pa_time); void psys_get_particle_on_path(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, int pa_num, struct ParticleKey *state, int vel); int psys_get_particle_state(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, int p, struct ParticleKey *state, int always); diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 1aceca454d2..6c1b8eb9000 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -786,8 +786,9 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p BLI_srandom(31415926 + psys->seed); lay= scene->lay; - if((part->draw_as == PART_DRAW_OB && part->dup_ob) || - (part->draw_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first)) { + if((psys->renderdata || part->draw_as==PART_DRAW_REND) && + ((part->ren_as == PART_DRAW_OB && part->dup_ob) || + (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first))) { /* if we have a hair particle system, use the path cache */ if(part->type == PART_HAIR) { @@ -804,7 +805,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p psys->lattice = psys_get_lattice(scene, par, psys); /* gather list of objects or single object */ - if(part->draw_as==PART_DRAW_GR) { + if(part->ren_as==PART_DRAW_GR) { group_handle_recalc_and_update(scene, par, part->dup_group); for(go=part->dup_group->gobject.first; go; go=go->next) @@ -850,7 +851,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p size = psys_get_child_size(psys, cpa, ctime, 0); } - if(part->draw_as==PART_DRAW_GR) { + if(part->ren_as==PART_DRAW_GR) { /* for groups, pick the object based on settings */ if(part->draw&PART_DRAW_RAND_GR) b= BLI_rand() % totgroup; @@ -894,7 +895,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p pamat[3][3]= 1.0f; } - if(part->draw_as==PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { + if(part->ren_as==PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { for(go= part->dup_group->gobject.first, b=0; go; go= go->next, b++) { Mat4MulMat4(tmat, oblist[b]->obmat, pamat); Mat4MulFloat3((float *)tmat, size*scale); @@ -930,7 +931,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p } /* restore objects since they were changed in where_is_object_time */ - if(part->draw_as==PART_DRAW_GR) { + if(part->ren_as==PART_DRAW_GR) { for(a=0; adraw_as == PART_DRAW_OB && part->dup_ob) { + if(part->ren_as == PART_DRAW_OB && part->dup_ob) { node2 = dag_get_node(dag, part->dup_ob); dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualisation"); if(part->dup_ob->type == OB_MBALL) dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualisation"); } - if(part->draw_as == PART_DRAW_GR && part->dup_group) { + if(part->ren_as == PART_DRAW_GR && part->dup_group) { for(go=part->dup_group->gobject.first; go; go=go->next) { node2 = dag_get_node(dag, go->ob); dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Group Visualisation"); diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 9ecf3a32c2b..71428a9e947 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -6390,6 +6390,7 @@ static void particleSystemModifier_deformVerts( } if(psys){ + psmd->flag &= ~eParticleSystemFlag_psys_updated; particle_system_update(md->scene, ob, psys); psmd->flag |= eParticleSystemFlag_psys_updated; psmd->flag &= ~eParticleSystemFlag_DM_changed; @@ -6421,6 +6422,8 @@ static void particleInstanceModifier_initData(ModifierData *md) pimd->flag = eParticleInstanceFlag_Parents|eParticleInstanceFlag_Unborn| eParticleInstanceFlag_Alive|eParticleInstanceFlag_Dead; pimd->psys = 1; + pimd->position = 1.0f; + pimd->axis = 2; } static void particleInstanceModifier_copyData(ModifierData *md, ModifierData *target) @@ -6431,6 +6434,8 @@ static void particleInstanceModifier_copyData(ModifierData *md, ModifierData *ta tpimd->ob = pimd->ob; tpimd->psys = pimd->psys; tpimd->flag = pimd->flag; + tpimd->position = pimd->position; + tpimd->random_position = pimd->random_position; } static int particleInstanceModifier_dependsOnTime(ModifierData *md) @@ -6470,7 +6475,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier( MFace *mface, *orig_mface; MVert *mvert, *orig_mvert; int i,totvert, totpart=0, totface, maxvert, maxface, first_particle=0; - short track=ob->trackflag%3, trackneg; + short track=ob->trackflag%3, trackneg, axis = pimd->axis; float max_co=0.0, min_co=0.0, temp_co[3], cross[3]; trackneg=((ob->trackflag>2)?1:0); @@ -6508,7 +6513,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier( psys->lattice=psys_get_lattice(md->scene, ob, psys); - if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED)){ + if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED){ float min_r[3], max_r[3]; INIT_MINMAX(min_r, max_r); @@ -6533,33 +6538,50 @@ static DerivedMesh * particleInstanceModifier_applyModifier( /*change orientation based on object trackflag*/ VECCOPY(temp_co,mv->co); - mv->co[0]=temp_co[track]; - mv->co[1]=temp_co[(track+1)%3]; - mv->co[2]=temp_co[(track+2)%3]; + mv->co[axis]=temp_co[track]; + mv->co[(axis+1)%3]=temp_co[(track+1)%3]; + mv->co[(axis+2)%3]=temp_co[(track+2)%3]; + + if((psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) && pimd->flag & eParticleInstanceFlag_Path){ + float ran = 0.0f; + if(pimd->random_position != 0.0f) { + /* just use some static collection of random numbers */ + /* TODO: use something else that's unique to each instanced object */ + pa = psys->particles + (i/totvert)%totpart; + ran = pimd->random_position * 0.5 * (1.0f + pa->r_ave[0]); + } + + if(pimd->flag & eParticleInstanceFlag_KeepShape) { + state.time = pimd->position * (1.0f - ran); + } + else { + state.time=(mv->co[axis]-min_co)/(max_co-min_co) * pimd->position * (1.0f - ran); + + if(trackneg) + state.time=1.0f-state.time; + + mv->co[axis] = 0.0; + } - if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) && pimd->flag & eParticleInstanceFlag_Path){ - state.time=(mv->co[0]-min_co)/(max_co-min_co); - if(trackneg) - state.time=1.0f-state.time; psys_get_particle_on_path(md->scene, pimd->ob, psys,first_particle + i/totvert, &state,1); - mv->co[0] = 0.0; - Normalize(state.vel); - if(state.vel[0] < -0.9999 || state.vel[0] > 0.9999) { - state.rot[0] = 1.0; + /* TODO: incremental rotations somehow */ + if(state.vel[axis] < -0.9999 || state.vel[axis] > 0.9999) { + state.rot[0] = 1; state.rot[1] = state.rot[2] = state.rot[3] = 0.0f; } else { - /* a cross product of state.vel and a unit vector in x-direction */ - cross[0] = 0.0f; - cross[1] = -state.vel[2]; - cross[2] = state.vel[1]; + float temp[3] = {0.0f,0.0f,0.0f}; + temp[axis] = 1.0f; - /* state.vel[0] is the only component surviving from a dot product with a vector in x-direction*/ - VecRotToQuat(cross,saacos(state.vel[0]),state.rot); + Crossf(cross, temp, state.vel); + + /* state.vel[axis] is the only component surviving from a dot product with the axis */ + VecRotToQuat(cross,saacos(state.vel[axis]),state.rot); } + } else{ state.time=-1.0; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 5bf9335d211..6ab8d72aa6d 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -81,6 +81,10 @@ static void key_from_object(Object *ob, ParticleKey *key); static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float *fuv, float *orco, ParticleTexture *ptex, int event); +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); /* few helpers for countall etc. */ int count_particles(ParticleSystem *psys){ @@ -452,7 +456,7 @@ void psys_free(Object *ob, ParticleSystem * psys) for(tpsys=ob->particlesystem.first; tpsys; tpsys=tpsys->next){ if(tpsys->part) { - if(ELEM(tpsys->part->draw_as,PART_DRAW_OB,PART_DRAW_GR)) + if(ELEM(tpsys->part->ren_as,PART_DRAW_OB,PART_DRAW_GR)) { nr++; break; @@ -491,6 +495,7 @@ typedef struct ParticleRenderData { ChildParticle *child; ParticleCacheKey **pathcache; ParticleCacheKey **childcache; + ListBase pathcachebufs, childcachebufs; int totchild, totcached, totchildcache; DerivedMesh *dm; int totdmvert, totdmedge, totdmface; @@ -577,8 +582,12 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[][4], float data->child= psys->child; data->totchild= psys->totchild; data->pathcache= psys->pathcache; + data->pathcachebufs.first = psys->pathcachebufs.first; + data->pathcachebufs.last = psys->pathcachebufs.last; data->totcached= psys->totcached; data->childcache= psys->childcache; + data->childcachebufs.first = psys->childcachebufs.first; + data->childcachebufs.last = psys->childcachebufs.last; data->totchildcache= psys->totchildcache; if(psmd->dm) @@ -591,6 +600,8 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[][4], float psys->pathcache= NULL; psys->childcache= NULL; psys->totchild= psys->totcached= psys->totchildcache= 0; + psys->pathcachebufs.first = psys->pathcachebufs.last = NULL; + psys->childcachebufs.first = psys->childcachebufs.last = NULL; Mat4CpyMat4(data->winmat, winmat); Mat4MulMat4(data->viewmat, ob->obmat, viewmat); @@ -631,8 +642,12 @@ void psys_render_restore(Object *ob, ParticleSystem *psys) psys->child= data->child; psys->totchild= data->totchild; psys->pathcache= data->pathcache; + psys->pathcachebufs.first = data->pathcachebufs.first; + psys->pathcachebufs.last = data->pathcachebufs.last; psys->totcached= data->totcached; psys->childcache= data->childcache; + psys->childcachebufs.first = data->childcachebufs.first; + psys->childcachebufs.last = data->childcachebufs.last; psys->totchildcache= data->totchildcache; psmd->dm= data->dm; @@ -663,7 +678,7 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot) int *origindex, *facetotvert; int a, b, totorigface, totface, newtot, skipped; - if(part->draw_as!=PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND)) + if(part->ren_as!=PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND)) return tot; if(!ctx->psys->renderdata) return tot; @@ -1992,11 +2007,9 @@ 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, rough_t, cpa_1st[3], dvec[3]; + float co[3], orco[3], ornor[3], t, cpa_1st[3], dvec[3]; float branch_begin, branch_end, branch_prob, branchfac, rough_rand; - float pa_rough1, pa_rough2, pa_roughe; - float length, pa_length, pa_clump, pa_kink, pa_effector; - float max_length = 1.0f, cur_length = 0.0f; + float length, max_length = 1.0f, cur_length = 0.0f; float eff_length, eff_vec[3]; int k, cpa_num, guided = 0; short cpa_from; @@ -2059,9 +2072,11 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, psys_particle_on_emitter(ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,co,ornor,0,0,orco,0); - /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */ - VECCOPY(cpa_1st,co); - Mat4MulVecfl(ob->obmat,cpa_1st); + if(part->path_start==0.0f) { + /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */ + VECCOPY(cpa_1st,co); + Mat4MulVecfl(ob->obmat,cpa_1st); + } pa=0; } @@ -2098,43 +2113,13 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, #endif // XXX old animation system /* get different child parameters from textures & vgroups */ - ptex.length=part->length*(1.0f - part->randlength*cpa->rand[0]); - ptex.clump=1.0; - ptex.kink=1.0; - ptex.rough= 1.0; - ptex.exist= 1.0; - - 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); - - pa_length=ptex.length; - pa_clump=ptex.clump; - pa_kink=ptex.kink; - pa_rough1=ptex.rough; - pa_rough2=ptex.rough; - pa_roughe=ptex.rough; - pa_effector= 1.0f; + get_child_modifier_parameters(part, ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex); if(ptex.exist < cpa->rand[1]) { keys->steps = -1; return; } - if(ctx->vg_length) - pa_length*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_length); - if(ctx->vg_clump) - pa_clump*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_clump); - if(ctx->vg_kink) - pa_kink*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_kink); - if(ctx->vg_rough1) - pa_rough1*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough1); - if(ctx->vg_rough2) - pa_rough2*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough2); - if(ctx->vg_roughe) - pa_roughe*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_roughe); - if(ctx->vg_effector) - pa_effector*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_effector); - /* create the child path */ for(k=0,state=keys; k<=ctx->steps; k++,state++){ if(ctx->between){ @@ -2158,12 +2143,14 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, key[w]++; w++; } - if(k==0){ - /* calculate the offset between actual child root position and first position interpolated from parents */ - VECSUB(cpa_1st,cpa_1st,state->co); + if(part->path_start==0.0f) { + if(k==0){ + /* calculate the offset between actual child root position and first position interpolated from parents */ + VECSUB(cpa_1st,cpa_1st,state->co); + } + /* apply offset for correct positioning */ + VECADD(state->co,state->co,cpa_1st); } - /* apply offset for correct positioning */ - VECADD(state->co,state->co,cpa_1st); } else{ /* offset the child from the parent position */ @@ -2177,7 +2164,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, if(part->flag & PART_CHILD_EFFECT) { for(k=0,state=keys; k<=ctx->steps; k++,state++) { if(k) { - do_path_effectors(ctx->scene, ob, psys, cpa->pa[0], state, k, ctx->steps, keys->co, pa_effector, 0.0f, ctx->cfra, &eff_length, eff_vec); + do_path_effectors(ctx->scene, ob, psys, cpa->pa[0], state, k, ctx->steps, keys->co, ptex.effector, 0.0f, ctx->cfra, &eff_length, eff_vec); } else { VecSubf(eff_vec,(state+1)->co,state->co); @@ -2203,67 +2190,50 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, } /* apply different deformations to the child path */ - if(part->flag & PART_CHILD_EFFECT) - /* state is safe to cast, since only co and vel are used */ - guided = do_guide(ctx->scene, (ParticleKey*)state, cpa->parent, t, &(psys->effectors)); + do_child_modifiers(ctx->scene, ob, psys, part, &ptex, (ParticleKey *)par, par_rot, cpa, orco, (ParticleKey *)state, t); - if(guided==0){ - if(part->kink) - do_prekink((ParticleKey*)state, (ParticleKey*)par, par_rot, t, - part->kink_freq * pa_kink, part->kink_shape, part->kink_amp, part->kink, part->kink_axis, ob->obmat); - - do_clump((ParticleKey*)state, (ParticleKey*)par, t, part->clumpfac, part->clumppow, pa_clump); - } + /* TODO: better branching */ + //if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING) + // rough_t = t * rough_rand; + //else + // rough_t = t; - if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING) - rough_t = t * rough_rand; - else - rough_t = t; + /* TODO: better branching */ + //if(part->flag & PART_BRANCHING && ctx->between==0){ + // if(branch_prob > part->branch_thres){ + // branchfac=0.0f; + // } + // else{ + // if(part->flag & PART_SYMM_BRANCHING){ + // if(t < branch_begin || t > branch_end) + // branchfac=0.0f; + // else{ + // if((t-branch_begin)/(branch_end-branch_begin)<0.5) + // branchfac=2.0f*(t-branch_begin)/(branch_end-branch_begin); + // else + // branchfac=2.0f*(branch_end-t)/(branch_end-branch_begin); - if(part->rough1 != 0.0 && pa_rough1 != 0.0) - do_rough(orco, rough_t, pa_rough1*part->rough1, part->rough1_size, 0.0, (ParticleKey*)state); + // CLAMP(branchfac,0.0f,1.0f); + // } + // } + // else{ + // if(t < branch_begin){ + // branchfac=0.0f; + // } + // else{ + // branchfac=(t-branch_begin)/((1.0f-branch_begin)*0.5f); + // CLAMP(branchfac,0.0f,1.0f); + // } + // } + // } - if(part->rough2 != 0.0 && pa_rough2 != 0.0) - do_rough(cpa->rand, rough_t, pa_rough2*part->rough2, part->rough2_size, part->rough2_thres, (ParticleKey*)state); - - if(part->rough_end != 0.0 && pa_roughe != 0.0) - do_rough_end(cpa->rand, rough_t, pa_roughe*part->rough_end, part->rough_end_shape, (ParticleKey*)state, (ParticleKey*)par); - - if(part->flag & PART_BRANCHING && ctx->between==0){ - if(branch_prob > part->branch_thres){ - branchfac=0.0f; - } - else{ - if(part->flag & PART_SYMM_BRANCHING){ - if(t < branch_begin || t > branch_end) - branchfac=0.0f; - else{ - if((t-branch_begin)/(branch_end-branch_begin)<0.5) - branchfac=2.0f*(t-branch_begin)/(branch_end-branch_begin); - else - branchfac=2.0f*(branch_end-t)/(branch_end-branch_begin); - - CLAMP(branchfac,0.0f,1.0f); - } - } - else{ - if(t < branch_begin){ - branchfac=0.0f; - } - else{ - branchfac=(t-branch_begin)/((1.0f-branch_begin)*0.5f); - CLAMP(branchfac,0.0f,1.0f); - } - } - } - - if(itotpart) - VecLerpf(state->co, (pcache[i] + k)->co, state->co, branchfac); - else - /* this is not threadsafe, but should only happen for - * branching particles particles, which are not threaded */ - VecLerpf(state->co, (cache[i - psys->totpart] + k)->co, state->co, branchfac); - } + // if(itotpart) + // VecLerpf(state->co, (pcache[i] + k)->co, state->co, branchfac); + // else + // /* this is not threadsafe, but should only happen for + // * branching particles particles, which are not threaded */ + // VecLerpf(state->co, (cache[i - psys->totpart] + k)->co, state->co, branchfac); + //} /* we have to correct velocity because of kink & clump */ if(k>1){ @@ -2287,9 +2257,9 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, else{ /* initialize length calculation */ if(part->flag&PART_ABS_LENGTH) - max_length= part->abslength*pa_length; + max_length= part->abslength*ptex.length; else - max_length= pa_length; + max_length= ptex.length; cur_length= 0.0f; } @@ -2383,7 +2353,36 @@ 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. */ @@ -2409,7 +2408,7 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra 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[3] = {0.5f, 0.5f, 0.5f}; + float col[4] = {0.5f, 0.5f, 0.5f, 1.0f}; float prev_tangent[3], hairmat[4][4]; int k,i; int steps = (int)pow(2.0, (double)psys->part->draw_step); @@ -2419,12 +2418,17 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra float length, vec[3]; float *vg_effector= NULL, effector=0.0f; float *vg_length= NULL, pa_length=1.0f, max_length=1.0f, cur_length=0.0f; - float len, dvec[3]; + int keyed, baked; /* we don't have anything valid to create paths from so let's quit here */ - if((psys->flag & PSYS_HAIR_DONE)==0 && (psys->flag & PSYS_KEYED)==0) + if((psys->flag & PSYS_HAIR_DONE)==0 && (psys->flag & PSYS_KEYED)==0 && (psys->pointcache->flag & PTCACHE_BAKED)==0) return; + BLI_srandom(psys->seed); + + keyed = psys->flag & PSYS_KEYED; + baked = psys->pointcache->flag & PTCACHE_BAKED; + if(psys->renderdata) { steps = (int)pow(2.0, (double)psys->part->ren_step); } @@ -2488,7 +2492,8 @@ 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 = 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); } @@ -2499,13 +2504,19 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra ekey = edit->keys[i]; /*--get the first data points--*/ - if(psys->flag & PSYS_KEYED) { + if(keyed) { kkey[0] = pa->keys; kkey[1] = kkey[0] + 1; 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; @@ -2516,6 +2527,25 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); } + if(!edit) { + if(part->draw & PART_ABS_PATH_TIME) { + birthtime = MAX2(birthtime, part->path_start); + dietime = MIN2(dietime, part->path_end); + } + else { + float tb = birthtime; + birthtime = tb + part->path_start * (dietime - tb); + dietime = tb + part->path_end * (dietime - tb); + } + + if(birthtime >= dietime) { + cache[i]->steps = -1; + continue; + } + + dietime = birthtime + pa_length * (dietime - birthtime); + } + if(soft){ bp[0] = soft->bpoint + pa->bpi; bp[1] = bp[0] + 1; @@ -2527,13 +2557,16 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra t = birthtime + time * (dietime - birthtime); - if(psys->flag & PSYS_KEYED) { + if(keyed) { while(kkey[1]->time < t) { kkey[1]++; } 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]++; @@ -2548,17 +2581,19 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra bp_to_particle(keys + 1, bp[0], hkey[0]); bp_to_particle(keys + 2, bp[1], hkey[1]); } - else if(psys->flag & PSYS_KEYED) { + 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((psys->flag & PSYS_KEYED)==0) { + if(!keyed && !baked) { if(soft) { if(hkey[0] != pa->hair) bp_to_particle(keys, bp[0] - 1, hkey[0] - 1); @@ -2591,18 +2626,18 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra keytime = (t - keys[1].time) / dfra; /* convert velocity to timestep size */ - if(psys->flag & PSYS_KEYED){ + 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((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic 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(psys->flag & PSYS_KEYED){ + if(keyed || baked){ VecMulf(result.vel, frs_sec / dfra); } else if(soft==NULL) { /* softbody and keyed are allready in global space */ @@ -2717,28 +2752,6 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra } } - - if(!edit && !psys->totchild) { - /* check if path needs to be cut before actual end of data points */ - if(k){ - VECSUB(dvec,ca->co,(ca-1)->co); - if(part->flag&PART_ABS_LENGTH) - len=VecLength(dvec); - else - len=1.0f/(float)steps; - - k=check_path_length(k,cache[i],ca,max_length,&cur_length,len,dvec); - } - else{ - /* initialize length calculation */ - if(part->flag&PART_ABS_LENGTH) - max_length= part->abslength*pa_length; - else - max_length= pa_length; - - cur_length= 0.0f; - } - } } } @@ -2990,7 +3003,8 @@ static void default_particle_settings(ParticleSettings *part) part->type= PART_EMITTER; part->distr= PART_DISTR_JIT; - part->draw_as=PART_DRAW_DOT; + part->draw_as = PART_DRAW_REND; + part->ren_as = PART_DRAW_HALO; part->bb_uv_split=1; part->bb_align=PART_BB_VIEW; part->bb_split_offset=PART_BB_OFF_LINEAR; @@ -3046,6 +3060,8 @@ static void default_particle_settings(ParticleSettings *part) part->rough_end_shape=1.0; part->draw_line[0]=0.5; + part->path_start = 0.0f; + part->path_end = 1.0f; part->banking=1.0; part->max_bank=1.0; @@ -3282,7 +3298,7 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float if((event & mtex->pmapto) & MAP_PA_KINK) ptex->kink= texture_value_blend(def,ptex->kink,value,var,blend,neg & MAP_PA_KINK); if((event & mtex->pmapto) & MAP_PA_ROUGH) - ptex->rough= texture_value_blend(def,ptex->rough,value,var,blend,neg & MAP_PA_ROUGH); + ptex->rough1= ptex->rough2= ptex->roughe= texture_value_blend(def,ptex->rough1,value,var,blend,neg & MAP_PA_ROUGH); if((event & mtex->pmapto) & MAP_PA_DENS) ptex->exist= texture_value_blend(def,ptex->exist,value,var,blend,neg & MAP_PA_DENS); } @@ -3291,7 +3307,11 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float if(event & MAP_PA_LENGTH) { CLAMP(ptex->length,0.0,1.0); } if(event & MAP_PA_CLUMP) { CLAMP(ptex->clump,0.0,1.0); } if(event & MAP_PA_KINK) { CLAMP(ptex->kink,0.0,1.0); } - if(event & MAP_PA_ROUGH) { CLAMP(ptex->rough,0.0,1.0); } + if(event & MAP_PA_ROUGH) { + CLAMP(ptex->rough1,0.0,1.0); + CLAMP(ptex->rough2,0.0,1.0); + CLAMP(ptex->roughe,0.0,1.0); + } if(event & MAP_PA_DENS) { CLAMP(ptex->exist,0.0,1.0); } } void psys_get_texture(Object *ob, Material *ma, ParticleSystemModifierData *psmd, ParticleSystem *psys, ParticleData *pa, ParticleTexture *ptex, int event) @@ -3392,12 +3412,12 @@ float psys_get_size(Object *ob, Material *ma, ParticleSystemModifierData *psmd, return size*part->size; } -float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra) +float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra, float *birthtime, float *dietime) { ParticleSettings *part = psys->part; + float time, life; if(part->childtype==PART_CHILD_FACES){ - float time; int w=0; time=0.0; while(w<4 && cpa->pa[w]>=0){ @@ -3405,12 +3425,21 @@ float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra) w++; } - return (cfra-time)/(part->lifetime*(1.0f-part->randlife*cpa->rand[1])); + life = part->lifetime*(1.0f-part->randlife*cpa->rand[1]); } else{ ParticleData *pa = psys->particles + cpa->parent; - return (cfra-pa->time)/pa->lifetime; + + time = pa->time; + life = pa->lifetime; } + + if(birthtime) + *birthtime = time; + if(dietime) + *dietime = time+life; + + return (cfra-time)/life; } float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra, float *pa_time) { @@ -3427,7 +3456,7 @@ float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra, if(pa_time) time=*pa_time; else - time=psys_get_child_time(psys,cpa,cfra); + time=psys_get_child_time(psys,cpa,cfra,NULL,NULL); /* correction for lifetime */ calc_ipo(part->ipo, 100*time); @@ -3449,6 +3478,64 @@ float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra, return size; } +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->clump=1.0; + ptex->kink=1.0; + ptex->rough1= 1.0; + ptex->rough2= 1.0; + ptex->roughe= 1.0; + ptex->exist= 1.0; + ptex->effector= 1.0; + + 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); + + + if(ptex->exist < cpa->rand[1]) + return; + + if(ctx->vg_length) + ptex->length*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_length); + if(ctx->vg_clump) + ptex->clump*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_clump); + if(ctx->vg_kink) + ptex->kink*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_kink); + if(ctx->vg_rough1) + ptex->rough1*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough1); + if(ctx->vg_rough2) + ptex->rough2*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough2); + if(ctx->vg_roughe) + ptex->roughe*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_roughe); + 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) +{ + int guided = 0; + + if(part->flag & PART_CHILD_EFFECT) + /* state is safe to cast, since only co and vel are used */ + guided = do_guide(scene, (ParticleKey*)state, cpa->parent, t, &(psys->effectors)); + + if(guided==0){ + if(part->kink) + do_prekink(state, par, par_rot, t, part->kink_freq * ptex->kink, part->kink_shape, + part->kink_amp, part->kink, part->kink_axis, ob->obmat); + + do_clump(state, par, t, part->clumpfac, part->clumppow, ptex->clump); + } + + if(part->rough1 != 0.0 && ptex->rough1 != 0.0) + do_rough(orco, 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); + + 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); +} /* 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) { @@ -3460,7 +3547,8 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i ParticleTexture ptex; ParticleKey *kkey[2] = {NULL, NULL}; HairKey *hkey[2] = {NULL, NULL}; - ParticleKey *par=0, keys[4]; + ParticleKey *par=0, keys[4], tstate; + ParticleThreadContext ctx; /* fake thread context for child modifiers */ float t, real_t, dfra, keytime, frs_sec = scene->r.frs_sec; float co[3], orco[3]; @@ -3471,6 +3559,9 @@ 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 cached = !keyed && part->type != PART_HAIR; + float *cpa_fuv; int cpa_num; short cpa_from; //if(psys_in_edit_mode(scene, psys)){ @@ -3479,12 +3570,6 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i // edit=1; //} - /* user want's cubic interpolation but only without sb it possible */ - //if(interpolation==PART_INTER_CUBIC && baked && psys->softflag==OB_SB_ENABLE) - // interpolation=PART_INTER_BSPLINE; - //else if(baked==0) /* it doesn't make sense to use other types for keyed */ - // interpolation=PART_INTER_CUBIC; - t=state->time; CLAMP(t, 0.0, 1.0); @@ -3497,20 +3582,29 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i return; } - if(psys->flag & PSYS_KEYED) { + if(keyed) { kkey[0] = pa->keys; kkey[1] = kkey[0] + 1; - real_t = kkey[0]->time + t * (kkey[0][pa->totkey-1].time - kkey[0]->time); + 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; - real_t = hkey[0]->time + (hkey[0][pa->totkey-1].time - hkey[0]->time) * t; + 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(psys->flag & PSYS_KEYED) { + if(keyed) { while(kkey[1]->time < real_t) { kkey[1]++; } @@ -3519,6 +3613,14 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i 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]++; @@ -3529,63 +3631,35 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i hair_to_particle(keys + 2, hkey[1]); } - if((psys->flag & PSYS_KEYED)==0) { - //if(soft){ - // if(key[0] != sbel.keys) - // DB_copy_key(&k1,key[0]-1); - // else - // DB_copy_key(&k1,&k2); - //} - //else{ + if(!keyed && !cached) { if(hkey[0] != pa->hair) hair_to_particle(keys, hkey[0] - 1); else hair_to_particle(keys, hkey[0]); - //} - //if(soft){ - // if(key[1] != sbel.keys + sbel.totkey-1) - // DB_copy_key(&k4,key[1]+1); - // else - // DB_copy_key(&k4,&k3); - //} - //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]); } - //} - - //psys_get_particle_on_path(scene, bsys,p,t,bkey,ckey[0]); - - //if(part->rotfrom==PART_ROT_KEYS) - // QuatInterpol(state->rot,k2.rot,k3.rot,keytime); - //else{ - // /* TODO: different rotations */ - // float nvel[3]; - // VECCOPY(nvel,state->vel); - // VecMulf(nvel,-1.0f); - // vectoquat(nvel, OB_POSX, OB_POSZ, state->rot); - //} dfra = keys[2].time - keys[1].time; keytime = (real_t - keys[1].time) / dfra; /* convert velocity to timestep size */ - if(psys->flag & PSYS_KEYED){ + 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((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic interpolation */ + 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(psys->flag & PSYS_KEYED){ + if(keyed || cached){ VecMulf(state->vel, frs_sec / dfra); } else { @@ -3606,8 +3680,11 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i } else if(totchild){ //Mat4Invert(imat,ob->obmat); - + cpa=psys->child+p-totpart; + + if(state->time < 0.0f) + t = psys_get_child_time(psys, cpa, -state->time, NULL, NULL); if(totchild && part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){ totparent=(int)(totchild*part->parents*0.3); @@ -3624,7 +3701,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i /* get parent states */ while(w<4 && cpa->pa[w]>=0){ - keys[w].time = t; + keys[w].time = state->time; psys_get_particle_on_path(scene, ob, psys, cpa->pa[w], keys+w, 1); w++; } @@ -3650,7 +3727,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i else{ /* get the parent state */ - keys->time = t; + keys->time = state->time; psys_get_particle_on_path(scene, ob, psys, cpa->parent, keys,1); /* get the original coordinates (orco) for texture usage */ @@ -3672,15 +3749,11 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i #endif // XXX old animation system /* get different child parameters from textures & vgroups */ - ptex.clump=1.0; - ptex.kink=1.0; - - get_cpa_texture(psmd->dm,ma,cpa_num,cpa_fuv,orco,&ptex,MAP_PA_CLUMP|MAP_PA_KINK); - - pa_clump=ptex.clump; - pa_kink=ptex.kink; - - /* TODO: vertex groups */ + memset(&ctx, 0, sizeof(ParticleThreadContext)); + ctx.dm = psmd->dm; + ctx.ma = ma; + /* TODO: assign vertex groups */ + get_child_modifier_parameters(part, &ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex); if(between){ int w=0; @@ -3708,46 +3781,34 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i } par = keys; - //if(totparent){ - // if(p-totpart>=totparent){ - // key.time=t; - // psys_get_particle_on_path(ob,psys,totpart+cpa->parent,&key,1); - // bti->convert_dynamic_key(bsys,&key,par,cpar); - // } - // else - // par=0; - //} - //else - // DB_get_key_on_path(bsys,cpa->parent,t,par,cpar); + + if(vel) + copy_particle_key(&tstate, state, 1); /* apply different deformations to the child path */ - if(part->kink) - do_prekink(state, par, par->rot, t, part->kink_freq * pa_kink, part->kink_shape, - part->kink_amp, part->kink, part->kink_axis, ob->obmat); - - do_clump(state, par, t, part->clumpfac, part->clumppow, 1.0f); + do_child_modifiers(scene, ob, psys, part, &ptex, par, par->rot, cpa, orco, state, t); - if(part->rough1 != 0.0) - do_rough(orco, t, part->rough1, part->rough1_size, 0.0, state); + /* try to estimate correct velocity */ + if(vel){ + ParticleKey tstate; + float length = VecLength(state->vel); - if(part->rough2 != 0.0) - do_rough(cpa->rand, t, part->rough2, part->rough2_size, part->rough2_thres, state); + if(t>=0.001f){ + tstate.time=t-0.001f; + psys_get_particle_on_path(scene,ob,psys,p,&tstate,0); + VECSUB(state->vel,state->co,tstate.co); + Normalize(state->vel); + } + else{ + float length = VecLength(state->vel); + tstate.time=t+0.001f; + psys_get_particle_on_path(scene, ob,psys,p,&tstate,0); + VECSUB(state->vel,tstate.co,state->co); + Normalize(state->vel); + } - if(part->rough_end != 0.0) - do_rough_end(cpa->rand, t, part->rough_end, part->rough_end_shape, state, par); - - //if(vel){ - // if(t>=0.001f){ - // tstate.time=t-0.001f; - // psys_get_particle_on_path(scene,ob,psys,p,&tstate,0); - // VECSUB(state->vel,state->co,tstate.co); - // } - // else{ - // tstate.time=t+0.001f; - // psys_get_particle_on_path(scene, ob,psys,p,&tstate,0); - // VECSUB(state->vel,tstate.co,state->co); - // } - //} + VecMulf(state->vel, length); + } } } /* gets particle's state at a time, returns 1 if particle exists and can be seen and 0 if not */ @@ -3774,7 +3835,7 @@ int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psy pa=psys->particles+p; if(between){ - state->time = psys_get_child_time(psys,&psys->child[p-totpart],cfra); + state->time = psys_get_child_time(psys,&psys->child[p-totpart],cfra,NULL,NULL); if(always==0) if((state->time<0.0 && (part->flag & PART_UNBORN)==0) diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 591b6ca9be5..92b919f6b0e 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -4254,7 +4254,7 @@ static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModif } } - if((part->type==PART_HAIR || psys->flag&PSYS_KEYED) && ( psys_in_edit_mode(scene, psys) || (part->type==PART_HAIR + if((part->type==PART_HAIR || psys->flag&PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED) && ( psys_in_edit_mode(scene, psys) || (part->type==PART_HAIR || (part->ren_as == PART_DRAW_PATH && (part->draw_as == PART_DRAW_REND || psys->renderdata))))){ psys_cache_paths(scene, ob, psys, cfra, 0); @@ -4371,8 +4371,10 @@ static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *ps dietime = birthtime + (1 + pa->loop) * (pa->dietime - pa->time); /* update alive status and push events */ - if(pa->time > cfra) + if(pa->time > cfra) { pa->alive = PARS_UNBORN; + reset_particle(scene, pa, psys, psmd, ob, 0.0f, cfra, NULL, NULL, NULL); + } else if(dietime <= cfra){ if(dietime > psys->cfra){ state.time = dietime; @@ -4406,6 +4408,8 @@ static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *ps distribute_particles(scene, ob, psys, PART_FROM_CHILD); } + psys_update_path_cache(scene, ob,psmd,psys,cfra); + if(vg_size) MEM_freeN(vg_size); } @@ -4433,10 +4437,17 @@ void psys_changed_type(ParticleSystem *psys) if(ELEM3(part->draw_as, PART_DRAW_NOT, PART_DRAW_REND, PART_DRAW_PATH)==0) part->draw_as = PART_DRAW_REND; + + CLAMP(part->path_start, 0.0f, 100.0f); + CLAMP(part->path_end, 0.0f, 100.0f); } - else + else { free_hair(psys, 1); + CLAMP(part->path_start, part->sta, part->end + part->lifetime); + CLAMP(part->path_end, part->sta, part->end + part->lifetime); + } + psys->softflag= 0; psys_reset(psys, PSYS_RESET_ALL); @@ -4629,9 +4640,8 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle totpart = psys->part->totpart; totchild = get_psys_tot_child(scene, psys); - if(oldtotpart != totpart || (psys->part->childtype && oldtotchild != totchild)) { + if(oldtotpart != totpart || oldtotchild != totchild) { only_children_changed = (oldtotpart == totpart); - realloc_particles(ob, psys, totpart); alloc = 1; distr= 1; init= 1; @@ -4647,11 +4657,12 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle if(alloc) { realloc_particles(ob, psys, totpart); - if(usecache) + if(usecache && !only_children_changed) BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); } - distribute_particles(scene, ob, psys, part->from); + if(!only_children_changed) + distribute_particles(scene, ob, psys, part->from); if((psys->part->type == PART_HAIR) && !(psys->flag & PSYS_HAIR_DONE)) /* don't generate children while growing hair - waste of time */ @@ -4660,7 +4671,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle distribute_particles(scene, ob, psys, PART_FROM_CHILD); } - if(only_children_changed==0) { + if(!only_children_changed) { free_keyed_keys(psys); initialize_all_particles(ob, psys, psmd); @@ -4680,19 +4691,10 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle int result = get_particles_from_cache(scene, ob, psys, (float)framenr, &old_framenr); if(result == PTCACHE_READ_EXACT || result == PTCACHE_READ_INTERPOLATED) { - //if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) { - // psys_count_keyed_targets(ob,psys); - // set_keyed_keys(scene, ob, psys); - //} - cached_step(scene, ob, psmd, psys, cfra); psys->cfra=cfra; psys->recalc = 0; - //if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) { - // psys_update_path_cache(scene, ob, psmd, psys, framenr); - //} - cache->simframe= framenr; cache->flag |= PTCACHE_SIMULATION_VALID; diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 64473d07151..b8a0b111324 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1209,8 +1209,13 @@ void BKE_ptcache_make_cache(PTCacheBaker* baker) for(pid=pidlist.first; pid; pid=pid->next) { cache = pid->cache; if((cache->flag & PTCACHE_BAKED)==0) { - if(pid->type==PTCACHE_TYPE_PARTICLES) + if(pid->type==PTCACHE_TYPE_PARTICLES) { + /* skip hair particles */ + if(((ParticleSystem*)pid->data)->part->type == PART_HAIR) + continue; + psys_get_pointcache_start_end(scene, pid->data, &cache->startframe, &cache->endframe); + } if((cache->flag & PTCACHE_REDO_NEEDED || (cache->flag & PTCACHE_SIMULATION_VALID)==0) && ((cache->flag & PTCACHE_QUICK_CACHE)==0 || render || bake)) @@ -1265,6 +1270,10 @@ void BKE_ptcache_make_cache(PTCacheBaker* baker) BKE_ptcache_ids_from_object(&pidlist, base->object); for(pid=pidlist.first; pid; pid=pid->next) { + /* skip hair particles */ + if(pid->type==PTCACHE_TYPE_PARTICLES && ((ParticleSystem*)pid->data)->part->type == PART_HAIR) + continue; + cache = pid->cache; if(step > 1) @@ -1282,7 +1291,9 @@ void BKE_ptcache_make_cache(PTCacheBaker* baker) scene->r.framelen = frameleno; CFRA = cfrao; - scene_update_for_newframe(scene, scene->lay); + + if(bake) /* already on cfra unless baking */ + scene_update_for_newframe(scene, scene->lay); /* TODO: call redraw all windows somehow */ } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index c89f515f319..93de096e7b4 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9059,6 +9059,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) part->draw_as = PART_DRAW_REND; } } + part->path_end = 1.0f; } /* set old pointcaches to have disk cache flag */ for(ob = main->object.first; ob; ob= ob->id.next) { diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index d9bc2d4d426..1ce352444e6 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -487,7 +487,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Object *ob, ModifierData *md, i ParticleSystem *psys= ((ParticleSystemModifierData *)md)->psys; if(!(G.f & G_PARTICLEEDIT)) - if(ELEM3(psys->part->draw_as, PART_DRAW_PATH, PART_DRAW_GR, PART_DRAW_OB) && psys->pathcache) + if(ELEM3(psys->part->ren_as, PART_DRAW_PATH, PART_DRAW_GR, PART_DRAW_OB) && psys->pathcache) uiItemO(row, "Convert", 0, "OBJECT_OT_modifier_convert"); } else diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 8bdfaeb6519..eb723dcca6c 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -226,11 +226,11 @@ int ED_object_modifier_convert(ReportList *reports, Scene *scene, Object *ob, Mo psys=((ParticleSystemModifierData *)md)->psys; part= psys->part; - if(part->draw_as == PART_DRAW_GR || part->draw_as == PART_DRAW_OB) { + if(part->ren_as == PART_DRAW_GR || part->ren_as == PART_DRAW_OB) { ; // XXX make_object_duplilist_real(NULL); } else { - if(part->draw_as != PART_DRAW_PATH || psys->pathcache == 0) + if(part->ren_as != PART_DRAW_PATH || psys->pathcache == 0) return 0; totpart= psys->totcached; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 05490e2fce1..b38575b5ceb 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -2941,6 +2941,228 @@ static int drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *bas return retval; } +/* *********** text drawing for particles ************* */ +static ListBase pstrings= {NULL, NULL}; + +typedef struct ViewParticleString { + struct ViewParticleString *next, *prev; + float vec[3], col[4]; + char str[128]; + short mval[2]; + short xoffs; +} ViewParticleString; + + +void view3d_particle_text_draw_add(float x, float y, float z, char *str, short xoffs) +{ + ViewObjectString *vos= MEM_callocN(sizeof(ViewObjectString), "ViewObjectString"); + + BLI_addtail(&pstrings, vos); + BLI_strncpy(vos->str, str, 128); + vos->vec[0]= x; + vos->vec[1]= y; + vos->vec[2]= z; + glGetFloatv(GL_CURRENT_COLOR, vos->col); + vos->xoffs= xoffs; +} + +static void view3d_particle_text_draw(View3D *v3d, ARegion *ar) +{ + ViewObjectString *vos; + int tot= 0; + + /* project first and test */ + for(vos= pstrings.first; vos; vos= vos->next) { + project_short(ar, vos->vec, vos->mval); + if(vos->mval[0]!=IS_CLIPPED) + tot++; + } + + if(tot) { + RegionView3D *rv3d= ar->regiondata; + int a; + + if(rv3d->rflag & RV3D_CLIPPING) + for(a=0; a<6; a++) + glDisable(GL_CLIP_PLANE0+a); + + wmPushMatrix(); + ED_region_pixelspace(ar); + + if(v3d->zbuf) glDepthMask(0); + + for(vos= pstrings.first; vos; vos= vos->next) { + if(vos->mval[0]!=IS_CLIPPED) { + glColor3fv(vos->col); + BLF_draw_default((float)vos->mval[0]+vos->xoffs, (float)vos->mval[1], 2.0, vos->str); + } + } + + if(v3d->zbuf) glDepthMask(1); + + wmPopMatrix(); + + if(rv3d->rflag & RV3D_CLIPPING) + for(a=0; a<6; a++) + glEnable(GL_CLIP_PLANE0+a); + } + + if(pstrings.first) + BLI_freelistN(&pstrings); +} +typedef struct ParticleDrawData { + float *vdata, *vd; + float *ndata, *nd; + float *cdata, *cd; + float *vedata, *ved; + float *ma_r, *ma_g, *ma_b; +} ParticleDrawData; +static void draw_particle(ParticleKey *state, int draw_as, short draw, float pixsize, float imat[4][4], float *draw_line, ParticleBillboardData *bb, ParticleDrawData *pdd) +{ + float vec[3], vec2[3]; + float *vd = pdd->vd; + float *nd = pdd->nd; + float *cd = pdd->cd; + float ma_r; + float ma_g; + float ma_b; + + if(pdd->ma_r) { + ma_r = *pdd->ma_r; + ma_g = *pdd->ma_g; + ma_b = *pdd->ma_b; + } + + switch(draw_as){ + case PART_DRAW_DOT: + { + if(vd) { + VECCOPY(vd,state->co) pdd->vd+=3; + } + if(cd) { + cd[0]=ma_r; + cd[1]=ma_g; + cd[2]=ma_b; + pdd->cd+=3; + } + break; + } + case PART_DRAW_CROSS: + case PART_DRAW_AXIS: + { + vec[0]=2.0f*pixsize; + vec[1]=vec[2]=0.0; + QuatMulVecf(state->rot,vec); + if(draw_as==PART_DRAW_AXIS) { + cd[1]=cd[2]=cd[4]=cd[5]=0.0; + cd[0]=cd[3]=1.0; + cd[6]=cd[8]=cd[9]=cd[11]=0.0; + cd[7]=cd[10]=1.0; + cd[13]=cd[12]=cd[15]=cd[16]=0.0; + cd[14]=cd[17]=1.0; + cd+=18; + + VECCOPY(vec2,state->co); + } + else { + if(cd) { + cd[0]=cd[3]=cd[6]=cd[9]=cd[12]=cd[15]=ma_r; + cd[1]=cd[4]=cd[7]=cd[10]=cd[13]=cd[16]=ma_g; + cd[2]=cd[5]=cd[8]=cd[11]=cd[14]=cd[17]=ma_b; + pdd->cd+=18; + } + VECSUB(vec2,state->co,vec); + } + + VECADD(vec,state->co,vec); + VECCOPY(pdd->vd,vec); pdd->vd+=3; + VECCOPY(pdd->vd,vec2); pdd->vd+=3; + + vec[1]=2.0f*pixsize; + vec[0]=vec[2]=0.0; + QuatMulVecf(state->rot,vec); + if(draw_as==PART_DRAW_AXIS){ + VECCOPY(vec2,state->co); + } + else VECSUB(vec2,state->co,vec); + + VECADD(vec,state->co,vec); + VECCOPY(pdd->vd,vec); pdd->vd+=3; + VECCOPY(pdd->vd,vec2); pdd->vd+=3; + + vec[2]=2.0f*pixsize; + vec[0]=vec[1]=0.0; + QuatMulVecf(state->rot,vec); + if(draw_as==PART_DRAW_AXIS){ + VECCOPY(vec2,state->co); + } + else VECSUB(vec2,state->co,vec); + + VECADD(vec,state->co,vec); + + VECCOPY(pdd->vd,vec); pdd->vd+=3; + VECCOPY(pdd->vd,vec2); pdd->vd+=3; + break; + } + case PART_DRAW_LINE: + { + VECCOPY(vec,state->vel); + Normalize(vec); + if(draw & PART_DRAW_VEL_LENGTH) + VecMulf(vec,VecLength(state->vel)); + VECADDFAC(pdd->vd,state->co,vec,-draw_line[0]); pdd->vd+=3; + VECADDFAC(pdd->vd,state->co,vec,draw_line[1]); pdd->vd+=3; + if(cd) { + cd[0]=cd[3]=ma_r; + cd[1]=cd[4]=ma_g; + cd[2]=cd[5]=ma_b; + pdd->cd+=6; + } + break; + } + case PART_DRAW_CIRC: + { + if(pdd->ma_r) + glColor3f(ma_r,ma_g,ma_b); + drawcircball(GL_LINE_LOOP, state->co, pixsize, imat); + break; + } + case PART_DRAW_BB: + { + float xvec[3], yvec[3], zvec[3], bb_center[3]; + if(cd) { + cd[0]=cd[3]=cd[6]=cd[9]=ma_r; + cd[1]=cd[4]=cd[7]=cd[10]=ma_g; + cd[2]=cd[5]=cd[8]=cd[11]=ma_b; + pdd->cd+=12; + } + + + VECCOPY(bb->vec, state->co); + VECCOPY(bb->vel, state->vel); + + psys_make_billboard(bb, xvec, yvec, zvec, bb_center); + + VECADD(pdd->vd,bb_center,xvec); + VECADD(pdd->vd,pdd->vd,yvec); pdd->vd+=3; + + VECSUB(pdd->vd,bb_center,xvec); + VECADD(pdd->vd,pdd->vd,yvec); pdd->vd+=3; + + VECSUB(pdd->vd,bb_center,xvec); + VECSUB(pdd->vd,pdd->vd,yvec); pdd->vd+=3; + + VECADD(pdd->vd,bb_center,xvec); + VECSUB(pdd->vd,pdd->vd,yvec); pdd->vd+=3; + + VECCOPY(pdd->nd, zvec); pdd->nd+=3; + VECCOPY(pdd->nd, zvec); pdd->nd+=3; + VECCOPY(pdd->nd, zvec); pdd->nd+=3; + VECCOPY(pdd->nd, zvec); pdd->nd+=3; + break; + } + } +} /* unified drawing of all new particle systems draw types except dupli ob & group */ /* mostly tries to use vertex arrays for speed */ @@ -2951,7 +3173,7 @@ static int drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *bas /* 5. start filling the arrays */ /* 6. draw the arrays */ /* 7. clean up */ -static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, ParticleSystem *psys, int dt) +static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, ParticleSystem *psys, int ob_dt) { Object *ob=base->object; ParticleSystemModifierData *psmd; @@ -2959,14 +3181,15 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv ParticleData *pars, *pa; ParticleKey state, *states=0; ParticleBillboardData bb; + ParticleDrawData pdd; Material *ma; - float vel[3], vec[3], vec2[3], imat[4][4], bb_center[3]; - float timestep, pixsize=1.0, pa_size, pa_time, r_tilt; + float vel[3], imat[4][4]; + float timestep, pixsize=1.0, pa_size, r_tilt, r_length; + float pa_time, pa_birthtime, pa_dietime; float cfra= bsystem_time(scene, ob,(float)CFRA,0.0); - float *vdata=0, *vedata=0, *cdata=0, *ndata=0, *vd=0, *ved=0, *cd=0, *nd=0, xvec[3], yvec[3], zvec[3]; float ma_r=0.0f, ma_g=0.0f, ma_b=0.0f; - int a, totpart, totpoint=0, draw_as, totchild=0; - int select=ob->flag&SELECT, create_cdata=0; + int a, totpart, totpoint=0, totve=0, drawn, draw_as, totchild=0; + int select=ob->flag&SELECT, create_cdata=0, need_v=0; GLint polygonmode[2]; char val[32]; @@ -3015,13 +3238,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv else totchild=psys->totchild*part->disp/100; - ma= give_current_material(ob,part->omat); + memset(&pdd, 0, sizeof(ParticleDrawData)); - if(ma) { - ma_r = ma->r; - ma_g = ma->g; - ma_b = ma->b; - } + ma= give_current_material(ob,part->omat); if(v3d->zbuf) glDepthMask(1); @@ -3029,6 +3248,15 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv cpack(0xFFFFFF); else if((ma) && (part->draw&PART_DRAW_MAT_COL)) { glColor3f(ma->r,ma->g,ma->b); + + ma_r = ma->r; + ma_g = ma->g; + ma_b = ma->b; + + pdd.ma_r = &ma_r; + pdd.ma_g = &ma_g; + pdd.ma_b = &ma_b; + create_cdata = 1; } else @@ -3038,8 +3266,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv timestep= psys_get_timestep(part); - wmLoadMatrix(rv3d->viewmat); - if( (base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP) ) { float mat[4][4]; Mat4MulMat4(mat, psys->imat, ob->obmat); @@ -3119,6 +3345,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv break; case PART_DRAW_PATH: break; + case PART_DRAW_LINE: + need_v=1; + break; } if(part->draw & PART_DRAW_SIZE && part->draw_as!=PART_DRAW_CIRC){ Mat4CpyMat4(imat, rv3d->viewinv); @@ -3129,40 +3358,45 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv /* 4. */ 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) + tot_vec_size *= part->trail_count; if(draw_as!=PART_DRAW_CIRC) { switch(draw_as) { case PART_DRAW_AXIS: case PART_DRAW_CROSS: if(draw_as != PART_DRAW_CROSS || create_cdata) - cdata = MEM_callocN(tot_vec_size * 6, "particle_cdata"); - vdata = MEM_callocN(tot_vec_size * 6, "particle_vdata"); + pdd.cdata = MEM_callocN(tot_vec_size * 6, "particle_cdata"); + pdd.vdata = MEM_callocN(tot_vec_size * 6, "particle_vdata"); break; case PART_DRAW_LINE: if(create_cdata) - cdata = MEM_callocN(tot_vec_size * 2, "particle_cdata"); - vdata = MEM_callocN(tot_vec_size * 2, "particle_vdata"); + pdd.cdata = MEM_callocN(tot_vec_size * 2, "particle_cdata"); + pdd.vdata = MEM_callocN(tot_vec_size * 2, "particle_vdata"); break; case PART_DRAW_BB: if(create_cdata) - cdata = MEM_callocN(tot_vec_size * 4, "particle_cdata"); - vdata = MEM_callocN(tot_vec_size * 4, "particle_vdata"); - ndata = MEM_callocN(tot_vec_size * 4, "particle_vdata"); + pdd.cdata = MEM_callocN(tot_vec_size * 4, "particle_cdata"); + pdd.vdata = MEM_callocN(tot_vec_size * 4, "particle_vdata"); + pdd.ndata = MEM_callocN(tot_vec_size * 4, "particle_vdata"); break; default: if(create_cdata) - cdata=MEM_callocN(tot_vec_size, "particle_cdata"); - vdata=MEM_callocN(tot_vec_size, "particle_vdata"); + pdd.cdata=MEM_callocN(tot_vec_size, "particle_cdata"); + pdd.vdata=MEM_callocN(tot_vec_size, "particle_vdata"); } } - if(part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) - vedata = MEM_callocN(tot_vec_size * 2, "particle_vedata"); + if(part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) { + pdd.vedata = MEM_callocN(tot_vec_size * 2, "particle_vedata"); + need_v = 1; + } - vd=vdata; - ved=vedata; - cd=cdata; - nd=ndata; + pdd.vd= pdd.vdata; + pdd.ved= pdd.vedata; + pdd.cd= pdd.cdata; + pdd.nd= pdd.ndata; psys->lattice= psys_get_lattice(scene, ob, psys); } @@ -3176,6 +3410,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv if(pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) continue; pa_time=(cfra-pa->time)/pa->lifetime; + pa_birthtime=pa->time; + pa_dietime = pa->dietime; pa_size=pa->size; if((part->flag&PART_ABS_TIME)==0){ @@ -3209,12 +3445,13 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv #endif // XXX old animation system } - r_tilt=1.0f+pa->r_ave[0]; + r_tilt = 1.0f + pa->r_ave[0]; + r_length = 0.5f * (1.0f + pa->r_ave[1]); } else{ ChildParticle *cpa= &psys->child[a-totpart]; - pa_time=psys_get_child_time(psys,cpa,cfra); + pa_time=psys_get_child_time(psys,cpa,cfra,&pa_birthtime,&pa_dietime); if((part->flag&PART_ABS_TIME)==0) { if(ma && ma->ipo){ @@ -3238,148 +3475,80 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv pa_size=psys_get_child_size(psys,cpa,cfra,0); - r_tilt=2.0f*cpa->rand[2]; + r_tilt = 2.0f * cpa->rand[2]; + r_length = cpa->rand[1]; } if(draw_as!=PART_DRAW_PATH){ - state.time=cfra; - if(psys_get_particle_state(scene,ob,psys,a,&state,0)){ - if(psys->parent) - Mat4MulVecfl(psys->parent->obmat, state.co); + drawn = 0; + if(part->draw_as == PART_DRAW_REND && part->trail_count > 1) { + float length = part->path_end * (1.0 - part->randlength * r_length); + int trail_count = part->trail_count * (1.0 - part->randlength * r_length); + float ct = ((part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time) - length; + float dt = length / (trail_count ? (float)trail_count : 1.0f); + int i=0; - /* create actiual particle data */ - switch(draw_as){ - case PART_DRAW_DOT: - if(vd){ - VECCOPY(vd,state.co) vd+=3; - } - if(cd) { - cd[0]=ma_r; - cd[1]=ma_g; - cd[2]=ma_b; - cd+=3; - } - break; - case PART_DRAW_CROSS: - case PART_DRAW_AXIS: - vec[0]=2.0f*pixsize; - vec[1]=vec[2]=0.0; - QuatMulVecf(state.rot,vec); - if(draw_as==PART_DRAW_AXIS){ - cd[1]=cd[2]=cd[4]=cd[5]=0.0; - cd[0]=cd[3]=1.0; - cd[6]=cd[8]=cd[9]=cd[11]=0.0; - cd[7]=cd[10]=1.0; - cd[13]=cd[12]=cd[15]=cd[16]=0.0; - cd[14]=cd[17]=1.0; - cd+=18; + ct+=dt; + for(i=0; i < trail_count; i++, ct += dt) { + if(part->draw & PART_ABS_PATH_TIME) { + if(ct < pa_birthtime || ct > pa_dietime) + continue; + } + else if(ct < 0.0f || ct > 1.0f) + continue; - VECCOPY(vec2,state.co); - } - else { - if(cd) { - cd[0]=cd[3]=cd[6]=cd[9]=cd[12]=cd[15]=ma_r; - cd[1]=cd[4]=cd[7]=cd[10]=cd[13]=cd[16]=ma_g; - cd[2]=cd[5]=cd[8]=cd[11]=cd[14]=cd[17]=ma_b; - cd+=18; - } - VECSUB(vec2,state.co,vec); - } + state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : ct; + psys_get_particle_on_path(scene,ob,psys,a,&state,need_v); + + if(psys->parent) + Mat4MulVecfl(psys->parent->obmat, state.co); - VECADD(vec,state.co,vec); - VECCOPY(vd,vec); vd+=3; - VECCOPY(vd,vec2); vd+=3; - - vec[1]=2.0f*pixsize; - vec[0]=vec[2]=0.0; - QuatMulVecf(state.rot,vec); - if(draw_as==PART_DRAW_AXIS){ - VECCOPY(vec2,state.co); - } - else VECSUB(vec2,state.co,vec); + /* create actiual particle data */ + if(draw_as == PART_DRAW_BB) { + bb.size = pa_size; + bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt); + bb.time = ct; + } - VECADD(vec,state.co,vec); - VECCOPY(vd,vec); vd+=3; - VECCOPY(vd,vec2); vd+=3; + draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, &pdd); - vec[2]=2.0f*pixsize; - vec[0]=vec[1]=0.0; - QuatMulVecf(state.rot,vec); - if(draw_as==PART_DRAW_AXIS){ - VECCOPY(vec2,state.co); - } - else VECSUB(vec2,state.co,vec); - - VECADD(vec,state.co,vec); - - VECCOPY(vd,vec); vd+=3; - VECCOPY(vd,vec2); vd+=3; - break; - case PART_DRAW_LINE: - VECCOPY(vec,state.vel); - Normalize(vec); - if(part->draw & PART_DRAW_VEL_LENGTH) - VecMulf(vec,VecLength(state.vel)); - VECADDFAC(vd,state.co,vec,-part->draw_line[0]); vd+=3; - VECADDFAC(vd,state.co,vec,part->draw_line[1]); vd+=3; - if(cd) { - cd[0]=cd[3]=ma_r; - cd[1]=cd[4]=ma_g; - cd[2]=cd[5]=ma_b; - cd+=3; - } - break; - case PART_DRAW_CIRC: - if(create_cdata) - glColor3f(ma_r,ma_g,ma_b); - drawcircball(GL_LINE_LOOP, state.co, pixsize, imat); - break; - case PART_DRAW_BB: - if(cd) { - cd[0]=cd[3]=cd[6]=cd[9]=ma_r; - cd[1]=cd[4]=cd[7]=cd[10]=ma_g; - cd[2]=cd[5]=cd[8]=cd[11]=ma_b; - cd+=12; - } + totpoint++; + drawn = 1; + } + } + else + { + state.time=cfra; + if(psys_get_particle_state(scene,ob,psys,a,&state,0)){ + if(psys->parent) + Mat4MulVecfl(psys->parent->obmat, state.co); + /* create actiual particle data */ + if(draw_as == PART_DRAW_BB) { bb.size = pa_size; bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt); bb.time = pa_time; - VECCOPY(bb.vec, state.co); - VECCOPY(bb.vel, state.vel); + } - psys_make_billboard(&bb, xvec, yvec, zvec, bb_center); - - VECADD(vd,bb_center,xvec); - VECADD(vd,vd,yvec); vd+=3; + draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, &pdd); - VECSUB(vd,bb_center,xvec); - VECADD(vd,vd,yvec); vd+=3; - - VECSUB(vd,bb_center,xvec); - VECSUB(vd,vd,yvec); vd+=3; - - VECADD(vd,bb_center,xvec); - VECSUB(vd,vd,yvec); vd+=3; - - VECCOPY(nd, zvec); nd+=3; - VECCOPY(nd, zvec); nd+=3; - VECCOPY(nd, zvec); nd+=3; - VECCOPY(nd, zvec); nd+=3; - break; + totpoint++; + drawn = 1; } + } - totpoint++; - + if(drawn) { /* additional things to draw for each particle */ /* (velocity, size and number) */ - if(vedata){ - VECCOPY(ved,state.co); - ved+=3; + if(pdd.vedata){ + VECCOPY(pdd.ved,state.co); + pdd.ved+=3; VECCOPY(vel,state.vel); VecMulf(vel,timestep); - VECADD(ved,state.co,vel); - ved+=3; + VECADD(pdd.ved,state.co,vel); + pdd.ved+=3; + + totve++; } if(part->draw & PART_DRAW_SIZE){ @@ -3391,7 +3560,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv if(part->draw&PART_DRAW_NUM && !(G.f & G_RENDER_SHADOW)){ /* in path drawing state.co is the end point */ sprintf(val," %i",a); - view3d_object_text_draw_add(state.co[0], state.co[1], state.co[2], val, 0); + view3d_particle_text_draw_add(state.co[0], state.co[1], state.co[2], val, 0); } } } @@ -3408,7 +3577,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv glEnableClientState(GL_VERTEX_ARRAY); /* setup gl flags */ - if(dt > OB_WIRE) { + if(ob_dt > OB_WIRE) { glEnableClientState(GL_NORMAL_ARRAY); if(part->draw&PART_DRAW_MAT_COL) @@ -3436,7 +3605,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv if(path->steps > 0) { glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); - if(dt > OB_WIRE) { + if(ob_dt > OB_WIRE) { glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel); if(part->draw&PART_DRAW_MAT_COL) glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col); @@ -3452,7 +3621,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv path=cache[a]; glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); - if(dt > OB_WIRE) { + if(ob_dt > OB_WIRE) { glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel); if(part->draw&PART_DRAW_MAT_COL) glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col); @@ -3463,7 +3632,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv /* restore & clean up */ - if(dt > OB_WIRE) { + if(ob_dt > OB_WIRE) { if(part->draw&PART_DRAW_MAT_COL) glDisable(GL_COLOR_ARRAY); glDisable(GL_COLOR_MATERIAL); @@ -3479,16 +3648,17 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv glDisableClientState(GL_COLOR_ARRAY); /* setup created data arrays */ - if(vdata){ + if(pdd.vdata){ glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, vdata); + glVertexPointer(3, GL_FLOAT, 0, pdd.vdata); } else glDisableClientState(GL_VERTEX_ARRAY); - if(ndata && dt>OB_WIRE){ + /* billboards are drawn this way */ + if(pdd.ndata && ob_dt>OB_WIRE){ glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, 0, ndata); + glNormalPointer(GL_FLOAT, 0, pdd.ndata); glEnable(GL_LIGHTING); } else{ @@ -3496,9 +3666,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv glDisable(GL_LIGHTING); } - if(cdata){ + if(pdd.cdata){ glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(3, GL_FLOAT, 0, cdata); + glColorPointer(3, GL_FLOAT, 0, pdd.cdata); } /* draw created data arrays */ @@ -3511,7 +3681,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv glDrawArrays(GL_LINES, 0, 2*totpoint); break; case PART_DRAW_BB: - if(dt<=OB_WIRE) + if(ob_dt<=OB_WIRE) glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); glDrawArrays(GL_QUADS, 0, 4*totpoint); @@ -3522,14 +3692,14 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv } } - if(vedata){ + if(pdd.vedata){ glDisableClientState(GL_COLOR_ARRAY); cpack(0xC0C0C0); glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, vedata); + glVertexPointer(3, GL_FLOAT, 0, pdd.vedata); - glDrawArrays(GL_LINES, 0, 2*totpoint); + glDrawArrays(GL_LINES, 0, 2*totve); } glPolygonMode(GL_FRONT, polygonmode[0]); @@ -3544,14 +3714,14 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv if(states) MEM_freeN(states); - if(vdata) - MEM_freeN(vdata); - if(vedata) - MEM_freeN(vedata); - if(cdata) - MEM_freeN(cdata); - if(ndata) - MEM_freeN(ndata); + if(pdd.vdata) + MEM_freeN(pdd.vdata); + if(pdd.vedata) + MEM_freeN(pdd.vedata); + if(pdd.cdata) + MEM_freeN(pdd.cdata); + if(pdd.ndata) + MEM_freeN(pdd.ndata); psys->flag &= ~PSYS_DRAWING; @@ -3560,8 +3730,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv psys->lattice= NULL; } - wmLoadMatrix(rv3d->viewmat); - wmMultMatrix(ob->obmat); // bring back local matrix for dtx + if( (base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP) ) + wmLoadMatrix(rv3d->viewmat); } static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, ParticleSystem *psys, int dt) @@ -3596,8 +3766,6 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob if((v3d->flag & V3D_ZBUF_SELECT)==0) glDisable(GL_DEPTH_TEST); - wmLoadMatrix(rv3d->viewmat); - /* get selection theme colors */ UI_GetThemeColor3ubv(TH_VERTEX_SELECT, sel); UI_GetThemeColor3ubv(TH_VERTEX, nosel); @@ -3706,7 +3874,7 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob if(key->flag & PEK_HIDE) continue; sprintf(val," %.1f",*key->time); - view3d_object_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0); + view3d_particle_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0); } } } @@ -3729,7 +3897,7 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob if((pset->flag & PE_SHOW_TIME) && !(G.f & G_RENDER_SHADOW)){ sprintf(val," %.1f",*key->time); - view3d_object_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0); + view3d_particle_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0); } } } @@ -3744,7 +3912,6 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob glEnable(GL_DEPTH_TEST); glLineWidth(1.0f); - wmMultMatrix(ob->obmat); // bring back local matrix for dtx glPointSize(1.0); } @@ -5145,7 +5312,9 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) ) { ParticleSystem *psys; if(col || (ob->flag & SELECT)) cpack(0xFFFFFF); /* for visibility, also while wpaint */ - glDepthMask(GL_FALSE); + //glDepthMask(GL_FALSE); + + wmLoadMatrix(rv3d->viewmat); for(psys=ob->particlesystem.first; psys; psys=psys->next) draw_new_particle_system(scene, v3d, rv3d, base, psys, dt); @@ -5155,7 +5324,11 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) if(psys && !scene->obedit && psys_in_edit_mode(scene, psys)) draw_particle_edit(scene, v3d, rv3d, ob, psys, dt); } - glDepthMask(GL_TRUE); + view3d_particle_text_draw(v3d, ar); + + wmMultMatrix(ob->obmat); + + //glDepthMask(GL_TRUE); if(col) cpack(col); } diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 76f6b980aa2..1fa17760e8d 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -503,12 +503,14 @@ typedef enum { eParticleInstanceFlag_Unborn = (1<<3), eParticleInstanceFlag_Alive = (1<<4), eParticleInstanceFlag_Dead = (1<<5), + eParticleInstanceFlag_KeepShape = (1<<6), } ParticleInstanceModifierFlag; typedef struct ParticleInstanceModifierData { ModifierData modifier; struct Object *ob; - short psys, flag, rt[2]; + short psys, flag, axis, rt; + float position, random_position; } ParticleInstanceModifierData; typedef enum { diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index 05f1cc1f351..c793362c223 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -131,7 +131,7 @@ typedef struct ParticleSettings { /* general values */ float sta, end, lifetime, randlife; - float timetweak, jitfac, keyed_time, eff_hair, rt; + float timetweak, jitfac, keyed_time, eff_hair; int totpart, userjit, grid_res; /* initial velocity factors */ @@ -159,6 +159,8 @@ typedef struct ParticleSettings { float branch_thres; /* drawing stuff */ float draw_line[2]; + float path_start, path_end; + int trail_count; /* boids */ float max_vel, max_lat_acc, max_tan_acc; @@ -311,8 +313,8 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in #define PART_DRAW_SIZE 4 #define PART_DRAW_EMITTER 8 /* render emitter also */ //#define PART_DRAW_HEALTH 16 -//#define PART_DRAW_TIMED_PATH 32 -//#define PART_DRAW_CACHED_PATH 64 +#define PART_ABS_PATH_TIME 32 +//#define PART_DRAW_TRAIL 64 #define PART_DRAW_BB_LOCK 128 #define PART_DRAW_PARENT 256 #define PART_DRAW_NUM 512 diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 48bfdf70171..f4c14a51b13 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1300,6 +1300,13 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; + static EnumPropertyItem particleinstance_axis[] = { + {0, "X", 0, "X", ""}, + {1, "Y", 0, "Y", ""}, + {2, "Z", 0, "Z", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna= RNA_def_struct(brna, "ParticleInstanceModifier", "Modifier"); RNA_def_struct_ui_text(srna, "ParticleInstance Modifier", "Particle system instancing modifier."); RNA_def_struct_sdna(srna, "ParticleInstanceModifierData"); @@ -1316,6 +1323,12 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna) RNA_def_property_range(prop, 1, 10); RNA_def_property_ui_text(prop, "Particle System Number", ""); RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "axis"); + RNA_def_property_enum_items(prop, particleinstance_axis); + RNA_def_property_ui_text(prop, "Axis", "Pole axis for rotation"); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update"); prop= RNA_def_property(srna, "normal", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", eParticleInstanceFlag_Parents); @@ -1346,6 +1359,23 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", eParticleInstanceFlag_Dead); RNA_def_property_ui_text(prop, "Dead", "Show instances when particles are dead."); RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "keep_shape", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", eParticleInstanceFlag_KeepShape); + RNA_def_property_ui_text(prop, "Keep Shape", "Don't stretch the object."); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "position", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "position"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_text(prop, "Position", "Position along path."); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "random_position", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "random_position"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_text(prop, "Random Position", "Randomize position along path."); + RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update"); } static void rna_def_modifier_explode(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index d60a215b498..5c94c81da1f 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -151,6 +151,20 @@ static void rna_particle_settings_set(PointerRNA *ptr, PointerRNA value) if(psys->part) psys->part->id.us++; } +static void rna_Particle_abspathtime_update(bContext *C, PointerRNA *ptr) +{ + ParticleSettings *settings = (ParticleSettings*)ptr->data; + float delta = settings->end + settings->lifetime - settings->sta; + if(settings->draw & PART_ABS_PATH_TIME) { + settings->path_start = settings->sta + settings->path_start * delta; + settings->path_end = settings->sta + settings->path_end * delta; + } + else { + settings->path_start = (settings->path_start - settings->sta)/delta; + settings->path_end = (settings->path_end - settings->sta)/delta; + } + rna_Particle_redo(C, ptr); +} static void rna_PartSettings_start_set(struct PointerRNA *ptr, float value) { ParticleSettings *settings = (ParticleSettings*)ptr->data; @@ -189,7 +203,19 @@ static float rna_PartSetting_linelentail_get(struct PointerRNA *ptr) ParticleSettings *settings = (ParticleSettings*)ptr->data; return settings->draw_line[0]; } +static void rna_PartSetting_pathstartend_range(PointerRNA *ptr, float *min, float *max) +{ + ParticleSettings *settings = (ParticleSettings*)ptr->data; + if(settings->type==PART_HAIR) { + *min = 0.0f; + *max = (settings->draw & PART_ABS_PATH_TIME) ? 100.0f : 1.0; + } + else { + *min = (settings->draw & PART_ABS_PATH_TIME) ? settings->sta : 0.0f; + *max= (settings->draw & PART_ABS_PATH_TIME) ? MAXFRAMEF : 1.0f; + } +} static void rna_PartSetting_linelenhead_set(struct PointerRNA *ptr, float value) { ParticleSettings *settings = (ParticleSettings*)ptr->data; @@ -702,15 +728,15 @@ static void rna_def_particle_settings(BlenderRNA *brna) 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, "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, "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); @@ -836,15 +862,10 @@ static void rna_def_particle_settings(BlenderRNA *brna) //RNA_def_property_ui_text(prop, "Health", "Draw boid health"); //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); - //prop= RNA_def_property(srna, "timed_path", PROP_BOOLEAN, PROP_NONE); - //RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_TIMED_PATH); - //RNA_def_property_ui_text(prop, "Clip with time", "Clip path based on time"); - //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); - - //prop= RNA_def_property(srna, "draw_cached_path", PROP_BOOLEAN, PROP_NONE); - //RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_CACHED_PATH); - //RNA_def_property_ui_text(prop, "Path", "Draw particle path if the path is baked"); - //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); + prop= RNA_def_property(srna, "abs_path_time", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_ABS_PATH_TIME); + RNA_def_property_ui_text(prop, "Absolute Path Time", "Path timing is in absolute frames"); + RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_abspathtime_update"); prop= RNA_def_property(srna, "billboard_lock", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_BB_LOCK); @@ -1410,6 +1431,24 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Head", "Length of the line's head"); RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); + prop= RNA_def_property(srna, "path_start", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "path_start"); + RNA_def_property_float_funcs(prop, NULL, NULL, "rna_PartSetting_pathstartend_range"); + RNA_def_property_ui_text(prop, "Path Start", "Starting time of drawn path."); + RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); + + prop= RNA_def_property(srna, "path_end", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "path_end"); + RNA_def_property_float_funcs(prop, NULL, NULL, "rna_PartSetting_pathstartend_range"); + RNA_def_property_ui_text(prop, "Path End", "End time of drawn path."); + RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo"); + + prop= RNA_def_property(srna, "trail_count", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "trail_count"); + 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"); + /* boids */ prop= RNA_def_property(srna, "max_velocity", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "max_vel"); diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index a00cd2211fc..74686511b21 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1246,6 +1246,19 @@ static void static_particle_wire(ObjectRen *obr, Material *ma, float *vec, float } +static void particle_curve(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd, float *loc, float *loc1, int seed) +{ + HaloRen *har=0; + + if(ma->mode&MA_WIRE) + static_particle_wire(obr, ma, loc, loc1, sd->first, sd->line); + else if(ma->material_type == MA_TYPE_HALO) { + har= RE_inithalo_particle(re, obr, dm, ma, loc, loc1, sd->orco, sd->uvco, sd->size, 1.0, seed); + if(har) har->lay= obr->ob->lay; + } + else + static_particle_strand(re, obr, ma, sd, loc, loc1); +} static void particle_billboard(Render *re, ObjectRen *obr, Material *ma, ParticleBillboardData *bb) { VlakRen *vlr; @@ -1368,18 +1381,55 @@ static void particle_billboard(Render *re, ObjectRen *obr, Material *ma, Particl mtf->uv[3][1] = uvy; } } -static void render_new_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd, float *loc, float *loc1, int seed) +static void particle_normal_ren(short ren_as, ParticleSettings *part, Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd, ParticleBillboardData *bb, ParticleKey *state, int seed, float hasize) { - HaloRen *har=0; + float loc[3], loc0[3], loc1[3], vel[3]; + + VECCOPY(loc, state->co); - if(ma->mode&MA_WIRE) - static_particle_wire(obr, ma, loc, loc1, sd->first, sd->line); - else if(ma->material_type == MA_TYPE_HALO) { - har= RE_inithalo_particle(re, obr, dm, ma, loc, loc1, sd->orco, sd->uvco, sd->size, 1.0, seed); - if(har) har->lay= obr->ob->lay; + if(ren_as != PART_DRAW_BB) + MTC_Mat4MulVecfl(re->viewmat, loc); + + switch(ren_as) { + case PART_DRAW_LINE: + sd->line = 1; + sd->time = 0.0f; + sd->size = hasize; + + VECCOPY(vel, state->vel); + MTC_Mat4Mul3Vecfl(re->viewmat, vel); + Normalize(vel); + + if(part->draw & PART_DRAW_VEL_LENGTH) + VecMulf(vel, VecLength(state->vel)); + + VECADDFAC(loc0, loc, vel, -part->draw_line[0]); + VECADDFAC(loc1, loc, vel, part->draw_line[1]); + + particle_curve(re, obr, dm, ma, sd, loc0, loc1, seed); + + break; + + case PART_DRAW_BB: + + VECCOPY(bb->vec, loc); + VECCOPY(bb->vel, state->vel); + + particle_billboard(re, obr, ma, bb); + + break; + + default: + { + HaloRen *har=0; + + har = RE_inithalo_particle(re, obr, dm, ma, loc, NULL, sd->orco, sd->uvco, hasize, 0.0, seed); + + if(har) har->lay= obr->ob->lay; + + break; + } } - else - static_particle_strand(re, obr, ma, sd, loc, loc1); } static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int num, ParticleStrandData *sd) { @@ -1436,9 +1486,10 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem StrandBound *sbound= 0; StrandRen *strand=0; RNG *rng= 0; - float loc[3],loc1[3],loc0[3],vel[3],mat[4][4],nmat[3][3],co[3],nor[3],time; + float loc[3],loc1[3],loc0[3],mat[4][4],nmat[3][3],co[3],nor[3],time; float strandlen=0.0f, curlen=0.0f; - float hasize, pa_size, pa_time, r_tilt, cfra=bsystem_time(re->scene, ob, (float)re->scene->r.cfra, 0.0); + float hasize, pa_size, r_tilt, r_length, cfra=bsystem_time(re->scene, ob, (float)re->scene->r.cfra, 0.0); + float pa_time, pa_birthtime, pa_dietime; float random, simplify[2]; int i, a, k, max_k=0, totpart, dosimplify = 0, dosurfacecache = 0; int totchild=0; @@ -1654,6 +1705,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem if(pa->flag & PARS_UNEXIST) continue; 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(ma->ipo) { @@ -1691,6 +1744,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem pa_size = pa->size; r_tilt = 1.0f + pa->r_ave[0]; + r_length = 0.5f * (1.0f + pa->r_ave[1]); if(path_nbr) { cache = psys->pathcache[a]; @@ -1711,7 +1765,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem max_k = (int)cache->steps; } - pa_time = psys_get_child_time(psys, cpa, cfra); + 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 @@ -1731,6 +1785,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem pa_size = psys_get_child_size(psys, cpa, cfra, &pa_time); r_tilt = 2.0f * cpa->rand[2]; + r_length = cpa->rand[1]; num = cpa->num; @@ -1864,14 +1919,14 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem VECSUB(loc0,loc1,loc); VECADD(loc0,loc1,loc0); - render_new_particle(re, obr, psmd->dm, ma, &sd, loc1, loc0, seed); + particle_curve(re, obr, psmd->dm, ma, &sd, loc1, loc0, seed); } sd.first = 0; sd.time = time; if(k) - render_new_particle(re, obr, psmd->dm, ma, &sd, loc, loc1, seed); + particle_curve(re, obr, psmd->dm, ma, &sd, loc, loc1, seed); VECCOPY(loc1,loc); } @@ -1880,61 +1935,55 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem } else { /* render normal particles */ - time=0.0f; - state.time=cfra; - if(psys_get_particle_state(re->scene,ob,psys,a,&state,0)==0) - continue; + if(part->trail_count > 1) { + float length = part->path_end * (1.0 - part->randlength * r_length); + int trail_count = part->trail_count * (1.0 - part->randlength * r_length); + float ct = (part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time; + float dt = length / (trail_count ? (float)trail_count : 1.0f); - if(psys->parent) - Mat4MulVecfl(psys->parent->obmat, state.co); + for(i=0; i < trail_count; i++, ct -= dt) { + if(part->draw & PART_ABS_PATH_TIME) { + if(ct < pa_birthtime || ct > pa_dietime) + continue; + } + else if(ct < 0.0f || ct > 1.0f) + continue; - VECCOPY(loc,state.co); - if(part->ren_as!=PART_DRAW_BB) - MTC_Mat4MulVecfl(re->viewmat,loc); + state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : ct; + psys_get_particle_on_path(re->scene,ob,psys,a,&state,1); - switch(part->ren_as) { - case PART_DRAW_LINE: - sd.line = 1; - sd.time = 0.0f; - sd.size = hasize; + if(psys->parent) + Mat4MulVecfl(psys->parent->obmat, state.co); - VECCOPY(vel,state.vel); - MTC_Mat4Mul3Vecfl(re->viewmat,vel); - Normalize(vel); + if(part->ren_as == PART_DRAW_BB) { + bb.random = random; + bb.size = pa_size; + bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt); + bb.time = ct; + bb.num = a; + } - if(part->draw & PART_DRAW_VEL_LENGTH) - VecMulf(vel,VecLength(state.vel)); + particle_normal_ren(part->ren_as, part, re, obr, psmd->dm, ma, &sd, &bb, &state, seed, hasize); + } + } + else { + time=0.0f; + state.time=cfra; + if(psys_get_particle_state(re->scene,ob,psys,a,&state,0)==0) + continue; - VECADDFAC(loc0,loc,vel,-part->draw_line[0]); - VECADDFAC(loc1,loc,vel,part->draw_line[1]); + if(psys->parent) + Mat4MulVecfl(psys->parent->obmat, state.co); - render_new_particle(re,obr,psmd->dm,ma,&sd,loc0,loc1,seed); - - break; - - case PART_DRAW_BB: + if(part->ren_as == PART_DRAW_BB) { bb.random = random; bb.size = pa_size; bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt); bb.time = pa_time; bb.num = a; - VECCOPY(bb.vec, loc); - VECCOPY(bb.vel, state.vel); - - particle_billboard(re, obr, ma, &bb); - - break; - - default: - { - HaloRen *har=0; - - har = RE_inithalo_particle(re, obr, psmd->dm, ma, loc, NULL, sd.orco, sd.uvco, hasize, 0.0, seed); - - if(har) har->lay= obr->ob->lay; - - break; } + + particle_normal_ren(part->ren_as, part, re, obr, psmd->dm, ma, &sd, &bb, &state, seed, hasize); } }