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.
This commit is contained in:
Janne Karhu 2009-07-04 03:50:12 +00:00
parent 2c71b12998
commit 66918b3add
Notes: blender-bot 2023-02-14 06:27:49 +01:00
Referenced by issue #70642, Bake All Dynamics not baking hair particles
Referenced by issue #53083, Bake All Dynamics doesn't work when baking particle hair
18 changed files with 974 additions and 564 deletions

View File

@ -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.")

View File

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

View File

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

View File

@ -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; a<totgroup; a++)
*(oblist[a])= obcopylist[a];
}

View File

@ -568,14 +568,14 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Keyed Physics");
}
if(part->draw_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");

View File

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

View File

@ -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(i<psys->totpart)
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(i<psys->totpart)
// 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)

View File

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

View File

@ -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 */
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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