diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-11-13 00:16:53 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-11-13 00:16:53 +0300 |
commit | bdfe7d89e2f1292644577972c716931b4ce3c6c3 (patch) | |
tree | d00eb50b749cb001e2b08272c91791e66740b05d /source/blender/blenkernel/intern/particle.c | |
parent | 78a1c27c4a6abe0ed31ca93ad21910f3df04da56 (diff) | |
parent | 7e4db234cee71ead34ee81a12e27da4bd548eb4b (diff) |
Merge of trunk into blender 2.5:
svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r12987:17416
Issues:
* GHOST/X11 had conflicting changes. Some code was added in 2.5, which was
later added in trunk also, but reverted partially, specifically revision
16683. I have left out this reversion in the 2.5 branch since I think it is
needed there.
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16683
* Scons had various conflicting changes, I decided to go with trunk version
for everything except priorities and some library renaming.
* In creator.c, there were various fixes and fixes for fixes related to the -w
-W and -p options. In 2.5 -w and -W is not coded yet, and -p is done
differently. Since this is changed so much, and I don't think those fixes
would be needed in 2.5, I've left them out.
* Also in creator.c: there was code for a python bugfix where the screen was not
initialized when running with -P. The code that initializes the screen there
I had to disable, that can't work in 2.5 anymore but left it commented as a
reminder.
Further I had to disable some new function calls. using src/ and python/, as
was done already in this branch, disabled function calls:
* bpath.c: error reporting
* BME_conversions.c: editmesh conversion functions.
* SHD_dynamic: disabled almost completely, there is no python/.
* KX_PythonInit.cpp and Ketsji/ build files: Mathutils is not there, disabled.
* text.c: clipboard copy call.
* object.c: OB_SUPPORT_MATERIAL.
* DerivedMesh.c and subsurf_ccg, stipple_quarttone.
Still to be done:
* Go over files and functions that were moved to a different location but could
still use changes that were done in trunk.
Diffstat (limited to 'source/blender/blenkernel/intern/particle.c')
-rw-r--r-- | source/blender/blenkernel/intern/particle.c | 1482 |
1 files changed, 899 insertions, 583 deletions
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index be69a0daaf7..32da154321e 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -46,6 +46,7 @@ #include "DNA_object_types.h" #include "DNA_curve_types.h" #include "DNA_key_types.h" +#include "DNA_ipo_types.h" #include "BLI_arithb.h" #include "BLI_blenlib.h" @@ -74,6 +75,7 @@ #include "BKE_modifier.h" #include "BKE_mesh.h" #include "BKE_cdderivedmesh.h" +#include "BKE_pointcache.h" #include "RE_render_ext.h" @@ -149,6 +151,49 @@ char *psys_menu_string(Object *ob, int for_sb) return str; } + +/* we allocate path cache memory in chunks instead of a big continguous + * chunk, windows' memory allocater fails to find big blocks of memory often */ + +#define PATH_CACHE_BUF_SIZE 1024 + +static ParticleCacheKey **psys_alloc_path_cache_buffers(ListBase *bufs, int tot, int steps) +{ + LinkData *buf; + ParticleCacheKey **cache; + int i, totkey, totbufkey; + + tot= MAX2(tot, 1); + totkey = 0; + cache = MEM_callocN(tot*sizeof(void*), "PathCacheArray"); + + while(totkey < tot) { + totbufkey= MIN2(tot-totkey, PATH_CACHE_BUF_SIZE); + buf= MEM_callocN(sizeof(LinkData), "PathCacheLinkData"); + buf->data= MEM_callocN(sizeof(ParticleCacheKey)*totbufkey*steps, "ParticleCacheKey"); + + for(i=0; i<totbufkey; i++) + cache[totkey+i] = ((ParticleCacheKey*)buf->data) + i*steps; + + totkey += totbufkey; + BLI_addtail(bufs, buf); + } + + return cache; +} + +static void psys_free_path_cache_buffers(ParticleCacheKey **cache, ListBase *bufs) +{ + LinkData *buf; + + if(cache) + MEM_freeN(cache); + + for(buf= bufs->first; buf; buf=buf->next) + MEM_freeN(buf->data); + BLI_freelistN(bufs); +} + /************************************************/ /* Getting stuff */ /************************************************/ @@ -199,7 +244,7 @@ Object *psys_get_lattice(Object *ob, ParticleSystem *psys) { Object *lattice=0; - if(!psys_in_edit_mode(psys)==0){ + if(psys_in_edit_mode(psys)==0){ ModifierData *md = (ModifierData*)psys_get_modifier(ob,psys); @@ -221,14 +266,14 @@ void psys_disable_all(Object *ob) ParticleSystem *psys=ob->particlesystem.first; for(; psys; psys=psys->next) - psys->flag &= ~PSYS_ENABLED; + psys->flag |= PSYS_DISABLED; } void psys_enable_all(Object *ob) { ParticleSystem *psys=ob->particlesystem.first; for(; psys; psys=psys->next) - psys->flag |= PSYS_ENABLED; + psys->flag &= ~PSYS_DISABLED; } int psys_ob_has_hair(Object *ob) { @@ -247,10 +292,17 @@ int psys_in_edit_mode(ParticleSystem *psys) int psys_check_enabled(Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd; + Mesh *me; - if(!(psys->flag & PSYS_ENABLED)) + if(psys->flag & PSYS_DISABLED || psys->flag & PSYS_DELETE) return 0; + if(ob->type == OB_MESH) { + me= (Mesh*)ob->data; + if(me->mr && me->mr->current != 1) + return 0; + } + psmd= psys_get_modifier(ob, psys); if(psys->renderdata) { if(!(psmd->modifier.mode & eModifierMode_Render)) @@ -267,10 +319,17 @@ int psys_check_enabled(Object *ob, ParticleSystem *psys) /************************************************/ void psys_free_settings(ParticleSettings *part) { - if(part->pd) + if(part->pd) { MEM_freeN(part->pd); + part->pd = NULL; + } + if(part->pd2) { + MEM_freeN(part->pd2); + part->pd2 = NULL; + } } -void free_hair(ParticleSystem *psys) + +void free_hair(ParticleSystem *psys, int softbody) { ParticleData *pa; int i, totpart=psys->totpart; @@ -282,6 +341,11 @@ void free_hair(ParticleSystem *psys) } psys->flag &= ~PSYS_HAIR_DONE; + + if(softbody && psys->soft) { + sbFree(psys->soft); + psys->soft = NULL; + } } void free_keyed_keys(ParticleSystem *psys) { @@ -290,39 +354,41 @@ void free_keyed_keys(ParticleSystem *psys) } void free_child_path_cache(ParticleSystem *psys) { - if(psys->childcache){ - if(psys->childcache[0]) - MEM_freeN(psys->childcache[0]); - - MEM_freeN(psys->childcache); - - psys->childcache = NULL; - psys->totchildcache = 0; - } + psys_free_path_cache_buffers(psys->childcache, &psys->childcachebufs); + psys->childcache = NULL; + psys->totchildcache = 0; } void psys_free_path_cache(ParticleSystem *psys) { - if(psys->pathcache){ - if(psys->pathcache[0]) - MEM_freeN(psys->pathcache[0]); - - MEM_freeN(psys->pathcache); + psys_free_path_cache_buffers(psys->pathcache, &psys->pathcachebufs); + psys->pathcache= NULL; + psys->totcached= 0; - psys->pathcache = NULL; - psys->totcached = 0; + free_child_path_cache(psys); +} +void psys_free_children(ParticleSystem *psys) +{ + if(psys->child) { + MEM_freeN(psys->child); + psys->child=0; + psys->totchild=0; } + free_child_path_cache(psys); } /* free everything */ void psys_free(Object *ob, ParticleSystem * psys) -{ +{ if(psys){ + int nr = 0; + ParticleSystem * tpsys; + if(ob->particlesystem.first == NULL && G.f & G_PARTICLEEDIT) G.f &= ~G_PARTICLEEDIT; psys_free_path_cache(psys); - free_hair(psys); + free_hair(psys, 1); free_keyed_keys(psys); @@ -342,17 +408,33 @@ void psys_free(Object *ob, ParticleSystem * psys) if(psys->effectors.first) psys_end_effectors(psys); + + // check if we are last non-visible particle system + for(tpsys=ob->particlesystem.first; tpsys; tpsys=tpsys->next){ + if(tpsys->part) + { + if(ELEM(tpsys->part->draw_as,PART_DRAW_OB,PART_DRAW_GR)) + { + nr++; + break; + } + } + } + // clear do-not-draw-flag + if(!nr) + ob->transflag &= ~OB_DUPLIPARTS; if(psys->part){ psys->part->id.us--; psys->part=0; } - if(psys->soft){ - sbFree(psys->soft); - psys->soft = 0; - } + if(psys->reactevents.first) + BLI_freelistN(&psys->reactevents); + if(psys->pointcache) + BKE_ptcache_free(psys->pointcache); + MEM_freeN(psys); } } @@ -362,7 +444,7 @@ void psys_free(Object *ob, ParticleSystem * psys) * removing the previous data. this should be solved properly once */ typedef struct ParticleRenderElem { - int curchild, totchild; + int curchild, totchild, reduce; float lambda, t, scalemin, scalemax; } ParticleRenderElem; @@ -379,6 +461,7 @@ typedef struct ParticleRenderData { int winx, winy; int dosimplify; + int timeoffset; ParticleRenderElem *elems; int *origindex; } ParticleRenderData; @@ -391,7 +474,7 @@ static float psys_render_viewport_falloff(double rate, float dist, float width) static float psys_render_projected_area(ParticleSystem *psys, float *center, float area, double vprate, float *viewport) { ParticleRenderData *data= psys->renderdata; - float co[3], view[3], ortho1[3], ortho2[2], w, dx, dy, radius; + float co[4], view[3], ortho1[3], ortho2[3], w, dx, dy, radius; /* transform to view space */ VECCOPY(co, center); @@ -440,13 +523,15 @@ static float psys_render_projected_area(ParticleSystem *psys, float *center, flo return area; } -void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[][4], float winmat[][4], int winx, int winy) +void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[][4], float winmat[][4], int winx, int winy, int timeoffset) { ParticleRenderData*data; ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys); if(!G.rendering) return; + if(psys->renderdata) + return; data= MEM_callocN(sizeof(ParticleRenderData), "ParticleRenderData"); @@ -474,6 +559,8 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[][4], float data->winx= winx; data->winy= winy; + data->timeoffset= timeoffset; + psys->renderdata= data; } @@ -515,8 +602,8 @@ void psys_render_restore(Object *ob, ParticleSystem *psys) psmd->totdmface= data->totdmface; psmd->flag &= ~eParticleSystemFlag_psys_updated; - if(psys->part->from==PART_FROM_FACE && psmd->dm) - psys_calc_dmfaces(ob, psmd->dm, psys); + if(psmd->dm) + psys_calc_dmcache(ob, psmd->dm, psys); MEM_freeN(data); psys->renderdata= NULL; @@ -531,7 +618,7 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot) ParticleRenderData *data; ParticleRenderElem *elems, *elem; ParticleSettings *part= ctx->psys->part; - float *facearea, (*facecenter)[3], size[3], fac, powrate; + float *facearea, (*facecenter)[3], size[3], fac, powrate, scaleclamp; float co1[3], co2[3], co3[3], co4[3], lambda, arearatio, t, area, viewport; double vprate; int *origindex, *facetotvert; @@ -539,7 +626,13 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot) if(part->draw_as!=PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND)) return tot; - if(!ctx->psys->renderdata || !(part->simplify_flag & PART_SIMPLIFY_ENABLE)) + if(!ctx->psys->renderdata) + return tot; + + data= ctx->psys->renderdata; + if(data->timeoffset) + return 0; + if(!(part->simplify_flag & PART_SIMPLIFY_ENABLE)) return tot; mvert= dm->getVertArray(dm); @@ -556,7 +649,9 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot) facetotvert= MEM_callocN(sizeof(int)*totorigface, "SimplifyFaceArea"); elems= MEM_callocN(sizeof(ParticleRenderElem)*totorigface, "SimplifyFaceElem"); - data= ctx->psys->renderdata; + if(data->elems) + MEM_freeN(data->elems); + data->dosimplify= 1; data->elems= elems; data->origindex= origindex; @@ -614,19 +709,30 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot) area = psys_render_projected_area(ctx->psys, facecenter[a], facearea[a], vprate, &viewport); arearatio= fac*area/facearea[a]; - if(arearatio < 1.0f || viewport < 1.0f) { + if((arearatio < 1.0f || viewport < 1.0f) && elem->totchild) { /* lambda is percentage of elements to keep */ lambda= (arearatio < 1.0f)? pow(arearatio, powrate): 1.0f; lambda *= viewport; + lambda= MAX2(lambda, 1.0f/elem->totchild); + /* compute transition region */ t= part->simplify_transition; elem->t= (lambda-t < 0.0f)? lambda: (lambda+t > 1.0f)? 1.0f-lambda: t; + elem->reduce= 1; /* scale at end and beginning of the transition region */ elem->scalemax= (lambda+t < 1.0f)? 1.0f/lambda: 1.0f/(1.0f - elem->t*elem->t/t); elem->scalemin= (lambda+t < 1.0f)? 0.0f: elem->scalemax*(1.0f-elem->t/t); + elem->scalemin= sqrt(elem->scalemin); + elem->scalemax= sqrt(elem->scalemax); + + /* clamp scaling */ + scaleclamp= MIN2(elem->totchild, 10.0f); + elem->scalemin= MIN2(scaleclamp, elem->scalemin); + elem->scalemax= MIN2(scaleclamp, elem->scalemax); + /* extend lambda to include transition */ lambda= lambda + elem->t; if(lambda > 1.0f) @@ -637,6 +743,7 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot) elem->scalemax= 1.0f; //sqrt(lambda); elem->scalemin= 1.0f; //sqrt(lambda); + elem->reduce= 0; } elem->lambda= lambda; @@ -698,7 +805,7 @@ int psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float scalemin= elem->scalemin; scalemax= elem->scalemax; - if(lambda >= 1.0f) { + if(!elem->reduce) { scale= scalemin; alpha= 1.0f; } @@ -746,7 +853,7 @@ static void weighted_particle_vector(float *v1, float *v2, float *v3, float *v4, vec[1]= weights[0]*v1[1] + weights[1]*v2[1] + weights[2]*v3[1] + weights[3]*v4[1]; vec[2]= weights[0]*v1[2] + weights[1]*v2[2] + weights[2]*v3[2] + weights[3]*v4[2]; } -static void interpolate_particle(short type, ParticleKey keys[4], float dt, ParticleKey *result) +static void interpolate_particle(short type, ParticleKey keys[4], float dt, ParticleKey *result, int velocity) { float t[4]; @@ -758,18 +865,20 @@ static void interpolate_particle(short type, ParticleKey keys[4], float dt, Part weighted_particle_vector(keys[0].co, keys[1].co, keys[2].co, keys[3].co, t, result->co); - //if(ve){ - // if(dt>0.999f){ - // set_four_ipo(dt+0.001f,t,ipo_type); - // weighted_particle_vector(key0->co,key1->co,key2->co,key3->co,t,temp); - // VECSUB(ve,temp,co); - // } - // else{ - // set_four_ipo(dt-0.001f,t,ipo_type); - // weighted_particle_vector(key0->co,key1->co,key2->co,key3->co,t,temp); - // VECSUB(ve,co,temp); - // } - //} + if(velocity){ + float temp[3]; + + if(dt>0.999f){ + set_four_ipo(dt-0.001f, t, type); + weighted_particle_vector(keys[0].co, keys[1].co, keys[2].co, keys[3].co, t, temp); + VECSUB(result->vel, result->co, temp); + } + else{ + set_four_ipo(dt+0.001f, t, type); + weighted_particle_vector(keys[0].co, keys[1].co, keys[2].co, keys[3].co, t, temp); + VECSUB(result->vel, temp, result->co); + } + } } } @@ -910,7 +1019,8 @@ void psys_interpolate_face(MVert *mvert, MFace *mface, MTFace *tface, float (*or } } } -void psys_interpolate_uvs(MTFace *tface, int quad, float *w, float *uvco){ +void psys_interpolate_uvs(MTFace *tface, int quad, float *w, float *uvco) +{ float v10= tface->uv[0][0]; float v11= tface->uv[0][1]; float v20= tface->uv[1][0]; @@ -931,9 +1041,35 @@ void psys_interpolate_uvs(MTFace *tface, int quad, float *w, float *uvco){ uvco[1]= w[0]*v11 + w[1]*v21 + w[2]*v31; } } + +void psys_interpolate_mcol(MCol *mcol, int quad, float *w, MCol *mc) +{ + char *cp, *cp1, *cp2, *cp3, *cp4; + + cp= (char *)mc; + cp1= (char *)&mcol[0]; + cp2= (char *)&mcol[1]; + cp3= (char *)&mcol[2]; + + if(quad) { + cp4= (char *)&mcol[3]; + + cp[0]= (int)(w[0]*cp1[0] + w[1]*cp2[0] + w[2]*cp3[0] + w[3]*cp4[0]); + cp[1]= (int)(w[0]*cp1[1] + w[1]*cp2[1] + w[2]*cp3[1] + w[3]*cp4[1]); + cp[2]= (int)(w[0]*cp1[2] + w[1]*cp2[2] + w[2]*cp3[2] + w[3]*cp4[2]); + cp[3]= (int)(w[0]*cp1[3] + w[1]*cp2[3] + w[2]*cp3[3] + w[3]*cp4[3]); + } + else { + cp[0]= (int)(w[0]*cp1[0] + w[1]*cp2[0] + w[2]*cp3[0]); + cp[1]= (int)(w[0]*cp1[1] + w[1]*cp2[1] + w[2]*cp3[1]); + cp[2]= (int)(w[0]*cp1[2] + w[1]*cp2[2] + w[2]*cp3[2]); + cp[3]= (int)(w[0]*cp1[3] + w[1]*cp2[3] + w[2]*cp3[3]); + } +} + float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int index, float *fw, float *values) { - if(values==0) + if(values==0 || index==-1) return 0.0; switch(from){ @@ -979,8 +1115,8 @@ static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, float *w, float } } -/* find the derived mesh face for a particle, set the mf passed. -This is slow, can be optimized but only for many lookups, return the face lookup index*/ +/* find the derived mesh face for a particle, set the mf passed. this is slow + * and can be optimized but only for many lookups. returns the face index. */ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, float *fw, struct LinkNode *node) { Mesh *me= (Mesh*)ob->data; @@ -1013,7 +1149,7 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, float * if(node) { /* we have a linked list of faces that we use, faster! */ for(;node; node=node->next) { - findex= (int)node->link; + findex= GET_INT_FROM_POINTER(node->link); faceuv= osface[findex].uv; quad= mface[findex].v4; @@ -1048,131 +1184,142 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, float * return DMCACHE_NOTFOUND; } -/* interprets particle data to get a point on a mesh in object space */ -#define PARTICLE_ERROR(_nor, _vec) _vec[0]=_vec[1]=_vec[2]=0.0; if(_nor){ _nor[0]=_nor[1]=0.0; _nor[2]=1.0; } -void psys_particle_on_dm(Object *ob, DerivedMesh *dm, int from, int index, int index_dmcache, float *fw, float foffset, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor) +static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache, float *fw, float foffset, int *mapindex, float *mapfw) { - float (*orcodata)[3]; - - if(index < 0){ /* 'no dm' error has happened! */ - PARTICLE_ERROR(nor, vec); - return; - } - orcodata= dm->getVertDataArray(dm, CD_ORCO); + if(index < 0) + return 0; if (dm->deformedOnly || index_dmcache == DMCACHE_ISCHILD) { - /* this works for meshes with deform verts only - constructive modifiers wont work properly*/ - float temp1[3]; - + /* for meshes that are either only defined or for child particles, the + * index and fw do not require any mapping, so we can directly use it */ if(from == PART_FROM_VERT) { - if(index >= dm->getNumVerts(dm)) { - PARTICLE_ERROR(nor, vec); - return; - } - - dm->getVertCo(dm,index,vec); - if(nor){ - dm->getVertNo(dm,index,nor); - Normalize(nor); - } - if(orco) - VECCOPY(orco, orcodata[index]) - if(ornor) { - dm->getVertNo(dm,index,nor); - Normalize(nor); - } - } - else { /* PART_FROM_FACE / PART_FROM_VOLUME */ - MFace *mface; - MTFace *mtface=0; - MVert *mvert; - int uv_index; - - if(index >= dm->getNumFaces(dm)) { - PARTICLE_ERROR(nor, vec); - return; - } - - mface=dm->getFaceData(dm,index,CD_MFACE); - mvert=dm->getVertDataArray(dm,CD_MVERT); - uv_index=CustomData_get_active_layer_index(&dm->faceData,CD_MTFACE); + if(index >= dm->getNumVerts(dm)) + return 0; - if(uv_index>=0){ - CustomDataLayer *layer=&dm->faceData.layers[uv_index]; - mtface= &((MTFace*)layer->data)[index]; - } + *mapindex = index; + } + else { /* FROM_FACE/FROM_VOLUME */ + if(index >= dm->getNumFaces(dm)) + return 0; - if(from==PART_FROM_VOLUME){ - psys_interpolate_face(mvert,mface,mtface,orcodata,fw,vec,temp1,utan,vtan,orco,ornor); - if(nor) - VECCOPY(nor,temp1); - Normalize(temp1); - VecMulf(temp1,-foffset); - VECADD(vec,vec,temp1); - } - else - psys_interpolate_face(mvert,mface,mtface,orcodata,fw,vec,nor,utan,vtan,orco,ornor); + *mapindex = index; + QUATCOPY(mapfw, fw); } } else { - /* Need to support constructive modifiers, this is a bit more tricky - we need a customdata layer like UV's so we can position the particle */ - - /* Only face supported at the moment */ - if (from==PART_FROM_FACE) { + /* for other meshes that have been modified, we try to map the particle + * to their new location, which means a different index, and for faces + * also a new face interpolation weights */ + if(from == PART_FROM_VERT) { + if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache > dm->getNumVerts(dm)) + return 0; + + *mapindex = index_dmcache; + } + else { /* FROM_FACE/FROM_VOLUME */ /* find a face on the derived mesh that uses this face */ - Mesh *me= (Mesh*)ob->data; - MVert *mvert; MFace *mface; - MTFace *mtface; OrigSpaceFace *osface; - int *origindex; - float fw_mod[4]; - int i, totface; - - mvert= dm->getVertDataArray(dm,CD_MVERT); + int i; + + i = index_dmcache; + + if(i== DMCACHE_NOTFOUND || i >= dm->getNumFaces(dm)) + return 0; + + *mapindex = i; + /* modify the original weights to become + * weights for the derived mesh face */ osface= dm->getFaceDataArray(dm, CD_ORIGSPACE); - origindex= dm->getFaceDataArray(dm, CD_ORIGINDEX); + mface= dm->getFaceData(dm, i, CD_MFACE); - /* For this to work we need origindex and OrigSpace coords */ - if(origindex==NULL || osface==NULL || index>=me->totface) { - PARTICLE_ERROR(nor, vec); - return; - } - - if (index_dmcache == DMCACHE_NOTFOUND) - i = psys_particle_dm_face_lookup(ob, dm, index, fw, (LinkNode*)NULL); + if(osface == NULL) + mapfw[0]= mapfw[1]= mapfw[2]= mapfw[3]= 0.0f; else - i = index_dmcache; + psys_origspace_to_w(&osface[i], mface->v4, fw, mapfw); + } + } - totface = dm->getNumFaces(dm); + return 1; +} - /* Any time this happens, and the face has not been removed, - * its a BUG watch out for this error! */ - if (i==-1) { - printf("Cannot find original face %i\n", index); - PARTICLE_ERROR(nor, vec); - return; - } - else if(i >= totface) - return; +/* interprets particle data to get a point on a mesh in object space */ +void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache, float *fw, float foffset, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor) +{ + float tmpnor[3], mapfw[4]; + float (*orcodata)[3]; + int mapindex; - mface= dm->getFaceData(dm, i, CD_MFACE); - mtface= dm->getFaceData(dm, i, CD_MTFACE); - osface += i; + if(!psys_map_index_on_dm(dm, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) { + if(vec) { vec[0]=vec[1]=vec[2]=0.0; } + if(nor) { nor[0]=nor[1]=0.0; nor[2]=1.0; } + if(orco) { orco[0]=orco[1]=orco[2]=0.0; } + if(ornor) { ornor[0]=ornor[1]=0.0; ornor[2]=1.0; } + if(utan) { utan[0]=utan[1]=utan[2]=0.0; } + if(vtan) { vtan[0]=vtan[1]=vtan[2]=0.0; } - /* we need to modify the original weights to become weights for - * the derived mesh face */ - psys_origspace_to_w(osface, mface->v4, fw, fw_mod); - psys_interpolate_face(mvert,mface,mtface,orcodata,fw_mod,vec,nor,utan,vtan,orco,ornor); + return; + } + + orcodata= dm->getVertDataArray(dm, CD_ORCO); + + if(from == PART_FROM_VERT) { + dm->getVertCo(dm,mapindex,vec); + + if(nor) { + dm->getVertNo(dm,mapindex,nor); + Normalize(nor); } - else { - /* TODO PARTICLE - support verts and volume */ - PARTICLE_ERROR(nor, vec); + + if(orco) + VECCOPY(orco, orcodata[mapindex]) + + if(ornor) { + dm->getVertNo(dm,mapindex,nor); + Normalize(nor); } + + if(utan && vtan) { + utan[0]= utan[1]= utan[2]= 0.0f; + vtan[0]= vtan[1]= vtan[2]= 0.0f; + } + } + else { /* PART_FROM_FACE / PART_FROM_VOLUME */ + MFace *mface; + MTFace *mtface; + MVert *mvert; + + mface=dm->getFaceData(dm,mapindex,CD_MFACE); + mvert=dm->getVertDataArray(dm,CD_MVERT); + mtface=CustomData_get_layer(&dm->faceData,CD_MTFACE); + + if(mtface) + mtface += mapindex; + + if(from==PART_FROM_VOLUME) { + psys_interpolate_face(mvert,mface,mtface,orcodata,mapfw,vec,tmpnor,utan,vtan,orco,ornor); + if(nor) + VECCOPY(nor,tmpnor); + + Normalize(tmpnor); + VecMulf(tmpnor,-foffset); + VECADD(vec,vec,tmpnor); + } + else + psys_interpolate_face(mvert,mface,mtface,orcodata,mapfw,vec,nor,utan,vtan,orco,ornor); } } -#undef PARTICLE_ERROR + +float psys_particle_value_from_verts(DerivedMesh *dm, short from, ParticleData *pa, float *values) +{ + float mapfw[4]; + int mapindex; + + if(!psys_map_index_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, &mapindex, mapfw)) + return 0.0f; + + return psys_interpolate_value_from_verts(dm, from, mapindex, mapfw, values); +} ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys) { @@ -1193,7 +1340,7 @@ ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys) /* Particles on a shape */ /************************************************/ /* ready for future use */ -void psys_particle_on_shape(int distr, int index, float *fuv, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor) +static void psys_particle_on_shape(int distr, int index, float *fuv, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor) { /* TODO */ float zerovec[3]={0.0f,0.0f,0.0f}; @@ -1219,16 +1366,16 @@ void psys_particle_on_shape(int distr, int index, float *fuv, float *vec, float /************************************************/ /* Particles on emitter */ /************************************************/ -void psys_particle_on_emitter(Object *ob, ParticleSystemModifierData *psmd, int from, int index, int index_dmcache, float *fuv, float foffset, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor){ +void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int index, int index_dmcache, float *fuv, float foffset, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor){ if(psmd){ - if(psmd->psys->part->distr==PART_DISTR_GRID){ + if(psmd->psys->part->distr==PART_DISTR_GRID && psmd->psys->part->from != PART_FROM_VERT){ if(vec){ VECCOPY(vec,fuv); } return; } /* we cant use the num_dmcache */ - psys_particle_on_dm(ob, psmd->dm,from,index,index_dmcache,fuv,foffset,vec,nor,utan,vtan,orco,ornor); + psys_particle_on_dm(psmd->dm,from,index,index_dmcache,fuv,foffset,vec,nor,utan,vtan,orco,ornor); } else psys_particle_on_shape(from,index,fuv,vec,nor,utan,vtan,orco,ornor); @@ -1263,7 +1410,7 @@ static float vert_weight(MDeformVert *dvert, int group) } static void do_prekink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, short type, short axis, float obmat[][4]) { - float vec[3]={0.0,0.0,0.0}, q1[4]={1,0,0,0},*q2; + float vec[3]={0.0,0.0,0.0}, q1[4]={1,0,0,0},q2[4]; float t; CLAMP(time,0.0,1.0); @@ -1285,10 +1432,9 @@ static void do_prekink(ParticleKey *state, ParticleKey *par, float *par_rot, flo case PART_KINK_CURL: vec[axis]=1.0; if(par_rot) - q2=par_rot; - else{ - q2=vectoquat(par->vel,axis,(axis+1)%3); - } + QUATCOPY(q2,par_rot) + else + vectoquat(par->vel,axis,(axis+1)%3, q2); QuatMulVecf(q2,vec); VecMulf(vec,amplitude); VECADD(state->co,state->co,vec); @@ -1335,9 +1481,9 @@ static void do_prekink(ParticleKey *state, ParticleKey *par, float *par_rot, flo float inp_y,inp_z,length; if(par_rot) - q2=par_rot; + QUATCOPY(q2,par_rot) else - q2=vectoquat(par->vel,axis,(axis+1)%3); + vectoquat(par->vel,axis,(axis+1)%3,q2); QuatMulVecf(q2,y_vec); QuatMulVecf(q2,z_vec); @@ -1394,59 +1540,6 @@ static void do_prekink(ParticleKey *state, ParticleKey *par, float *par_rot, flo } } break; - //case PART_KINK_ROT: - // vec[axis]=1.0; - - // QuatMulVecf(par->rot,vec); - - // VecMulf(vec,amplitude*(float)sin(t)); - - // VECADD(state->co,state->co,vec); - // break; - } -} -static void do_postkink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, short type, short axis, float obmat[][4]) -{ - static ParticleKey first; - static float q[4]; - float vec[3]={0.0,0.0,0.0}; - float t; - - CLAMP(time,0.0,1.0); - - t=time; - - t*=(float)M_PI*freq; - - if(par==0) return; - - switch(type){ - case PART_KINK_ROLL: - if(time<(0.5+shape/2.0f)){ - float *q2; - memcpy(&first,state,sizeof(ParticleKey)); - Normalize(first.vel); - if(par_rot) - q2=par_rot; - else - q2=vectoquat(par->vel,axis,(axis+1)%3); - QUATCOPY(q,q2); - } - else{ - float fac; - shape=0.5f+shape/2.0f; - t-=(float)M_PI*(shape*freq + 0.5f); - - vec[axis]=1.0; - - QuatMulVecf(q,vec); - - fac=amplitude*(1.0f+((1.0f-time)/(1.0f-shape)*(float)sin(t))); - VECADDFAC(state->co,first.co,vec,fac); - fac=amplitude*((1.0f-time)/(1.0f-shape)*(float)cos(t)); - VECADDFAC(state->co,state->co,first.vel,fac); - } - break; } } static void do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump) @@ -1539,7 +1632,7 @@ int do_guide(ParticleKey *state, int pa_num, float time, ListBase *lb) VecRotToQuat(guidedir,guidevec[3]-ec->firstloc[3],rot2); QuatMulVecf(rot2,pa_loc); - //q=vectoquat(guidedir, pd->kink_axis, (pd->kink_axis+1)%3); + //vectoquat(guidedir, pd->kink_axis, (pd->kink_axis+1)%3, q); //QuatMul(par.rot,rot2,q); } //else{ @@ -1553,13 +1646,11 @@ int do_guide(ParticleKey *state, int pa_num, float time, ListBase *lb) /* TODO */ //else{ ///* curve size*/ - // calc_curve_subdiv_radius(cu,cu->nurb.first,((Nurb*)cu->nurb.first)-> //} par.co[0]=par.co[1]=par.co[2]=0.0f; VECCOPY(key.co,pa_loc); do_prekink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, pd->kink, pd->kink_axis, 0); do_clump(&key, &par, guidetime, pd->clump_fac, pd->clump_pow, 1.0f); - do_postkink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, pd->kink, pd->kink_axis, 0); VECCOPY(pa_loc,key.co); VECADD(pa_loc,pa_loc,guidevec); @@ -1626,40 +1717,46 @@ static void do_rough_end(float *loc, float t, float fac, float shape, ParticleKe VECADD(state->co,state->co,rough); } +static void do_path_effectors(Object *ob, ParticleSystem *psys, int i, ParticleCacheKey *ca, int k, int steps, float *rootco, float effector, float dfra, float cfra, float *length, float *vec) +{ + float force[3] = {0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f}; + ParticleKey eff_key; + ParticleData *pa; + + VECCOPY(eff_key.co,(ca-1)->co); + VECCOPY(eff_key.vel,(ca-1)->vel); + QUATCOPY(eff_key.rot,(ca-1)->rot); + + pa= psys->particles+i; + do_effectors(i, pa, &eff_key, ob, psys, rootco, force, vel, dfra, cfra); + + VecMulf(force, effector*pow((float)k / (float)steps, 100.0f * psys->part->eff_hair) / (float)steps); + + VecAddf(force, force, vec); + + Normalize(force); + + if(k < steps) { + VecSubf(vec, (ca+1)->co, ca->co); + *length = VecLength(vec); + } + + VECADDFAC(ca->co, (ca-1)->co, force, *length); +} static int check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *state, float max_length, float *cur_length, float length, float *dvec) { if(*cur_length + length > max_length){ - //if(p<totparent){ - // if(k<=(int)cache[totpart+p]->time){ - // /* parents need to be calculated fully first so that they don't mess up their children */ - // /* we'll make a note of where we got to though so that they're easy to finish later */ - // state->time=(max_length-*cur_length)/length; - // cache[totpart+p]->time=(float)k; - // } - //} - //else{ VecMulf(dvec, (max_length - *cur_length) / length); VECADD(state->co, (state - 1)->co, dvec); keys->steps = k; /* something over the maximum step value */ return k=100000; - //} } else { *cur_length+=length; return k; } } -static void finalize_path_length(ParticleCacheKey *keys) -{ - ParticleCacheKey *state = keys; - float dvec[3]; - state += state->steps; - - VECSUB(dvec, state->co, (state - 1)->co); - VecMulf(dvec, state->steps); - VECADD(state->co, (state - 1)->co, dvec); -} static void offset_child(ChildParticle *cpa, ParticleKey *par, ParticleKey *child, float flat, float radius) { VECCOPY(child->co,cpa->fuv); @@ -1709,14 +1806,14 @@ void psys_find_parents(Object *ob, ParticleSystemModifierData *psmd, ParticleSys tree=BLI_kdtree_new(totparent); for(p=0,cpa=psys->child; p<totparent; p++,cpa++){ - psys_particle_on_emitter(ob,psmd,from,cpa->num,-1,cpa->fuv,cpa->foffset,co,0,0,0,orco,0); + psys_particle_on_emitter(psmd,from,cpa->num,-1,cpa->fuv,cpa->foffset,co,0,0,0,orco,0); BLI_kdtree_insert(tree, p, orco, NULL); } BLI_kdtree_balance(tree); for(; p<totchild; p++,cpa++){ - psys_particle_on_emitter(ob,psmd,from,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co,0,0,0,orco,0); + psys_particle_on_emitter(psmd,from,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co,0,0,0,orco,0); cpa->parent=BLI_kdtree_find_nearest(tree, orco, NULL, NULL); } @@ -1817,6 +1914,8 @@ int psys_threads_init_path(ParticleThread *threads, float cfra, int editupdate) ctx->vg_rough1 = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_ROUGH1); ctx->vg_rough2 = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_ROUGH2); ctx->vg_roughe = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_ROUGHE); + if(psys->part->flag & PART_CHILD_EFFECT) + ctx->vg_effector = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_EFFECTOR); } /* set correct ipo timing */ @@ -1838,14 +1937,15 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, ParticleCacheKey **cache= psys->childcache; ParticleCacheKey **pcache= psys->pathcache; ParticleCacheKey *state, *par = NULL, *key[4]; - ParticleData *pa; + ParticleData *pa=NULL; ParticleTexture ptex; float *cpa_fuv=0; float co[3], orco[3], ornor[3], t, rough_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; + float length, pa_length, pa_clump, pa_kink, pa_effector; float max_length = 1.0f, cur_length = 0.0f; + float eff_length, eff_vec[3]; int k, cpa_num, guided=0; short cpa_from; @@ -1905,7 +2005,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, cpa_fuv = cpa->fuv; cpa_from = PART_FROM_FACE; - psys_particle_on_emitter(ob,ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,co,ornor,0,0,orco,0); + 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); @@ -1931,7 +2031,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, cpa_num=pa->num; cpa_fuv=pa->fuv; - psys_particle_on_emitter(ob,ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,ornor,0,0,orco,0); + psys_particle_on_emitter(ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,ornor,0,0,orco,0); } keys->steps = ctx->steps; @@ -1958,6 +2058,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, pa_rough1=ptex.rough; pa_rough2=ptex.rough; pa_roughe=ptex.rough; + pa_effector= 1.0f; if(ctx->vg_length) pa_length*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_length); @@ -1971,16 +2072,17 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, 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++){ - t=(float)k/(float)ctx->steps; - if(ctx->between){ int w=0; state->co[0] = state->co[1] = state->co[2] = 0.0f; state->vel[0] = state->vel[1] = state->vel[2] = 0.0f; + state->rot[0] = state->rot[1] = state->rot[2] = state->rot[3] = 0.0f; //QUATCOPY(state->rot,key[0]->rot); @@ -2009,6 +2111,23 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, key[0]++; } + } + + /* apply effectors */ + if(part->flag & PART_CHILD_EFFECT) { + for(k=0,state=keys; k<=ctx->steps; k++,state++) { + if(k) { + do_path_effectors(ob, psys, cpa->pa[0], state, k, ctx->steps, keys->co, pa_effector, 0.0f, ctx->cfra, &eff_length, eff_vec); + } + else { + VecSubf(eff_vec,(state+1)->co,state->co); + eff_length= VecLength(eff_vec); + } + } + } + + for(k=0,state=keys; k<=ctx->steps; k++,state++){ + t=(float)k/(float)ctx->steps; if(ctx->totparent){ if(i>=ctx->totparent) @@ -2023,8 +2142,9 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, } /* apply different deformations to the child path */ - if(part->flag & PART_CHILD_GUIDE) - guided = do_guide((ParticleKey*)state, i, t, &(psys->effectors)); //safe to cast, since only co and vel are used + if(part->flag & PART_CHILD_EFFECT) + /* state is safe to cast, since only co and vel are used */ + guided = do_guide((ParticleKey*)state, cpa->parent, t, &(psys->effectors)); if(guided==0){ if(part->kink) @@ -2032,10 +2152,6 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, 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); - - if(part->kink) - do_postkink((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); } if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING) @@ -2044,7 +2160,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, rough_t = t; 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); + do_rough(orco, rough_t, pa_rough1*part->rough1, part->rough1_size, 0.0, (ParticleKey*)state); 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); @@ -2122,13 +2238,9 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, get_strand_normal(ctx->ma, ornor, cur_length, state->vel); } } - - /* now let's finalise the interpolated parents that we might have left half done before */ - if(i<ctx->totparent) - finalize_path_length(keys); } -void *exec_child_path_cache(void *data) +static void *exec_child_path_cache(void *data) { ParticleThread *thread= (ParticleThread*)data; ParticleThreadContext *ctx= thread->ctx; @@ -2149,11 +2261,11 @@ void psys_cache_child_paths(Object *ob, ParticleSystem *psys, float cfra, int ed ParticleSettings *part = psys->part; ParticleThread *pthreads; ParticleThreadContext *ctx; - ParticleCacheKey **cache, *tcache; + ParticleCacheKey **cache; ListBase threads; int i, totchild, totparent, totthread; - pthreads= psys_threads_create(ob, psys, G.scene->r.threads); + pthreads= psys_threads_create(ob, psys); if(!psys_threads_init_path(pthreads, cfra, editupdate)) { psys_threads_free(pthreads); @@ -2170,12 +2282,7 @@ void psys_cache_child_paths(Object *ob, ParticleSystem *psys, float cfra, int ed else { /* clear out old and create new empty path cache */ free_child_path_cache(psys); - - cache = psys->childcache = MEM_callocN(totchild*sizeof(void *), "Child path cache array"); - tcache = MEM_callocN(totchild * (ctx->steps + 1) * sizeof(ParticleCacheKey), "Child path cache"); - for(i=0; i<totchild; i++) - cache[i] = tcache + i * (ctx->steps + 1); - + psys->childcache= psys_alloc_path_cache_buffers(&psys->childcachebufs, totchild, ctx->steps+1); psys->totchildcache = totchild; } @@ -2204,6 +2311,7 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda ParticleCacheKey *ca, **cache=psys->pathcache; ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); ParticleEditSettings *pset = &G.scene->toolsettings->particle; + ParticleSettings *part = psys->part; ParticleData *pa; ParticleKey keys[4], result, *kkey[2] = {NULL, NULL}; @@ -2218,7 +2326,7 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda Material *ma; float birthtime = 0.0, dietime = 0.0; - float t, time, keytime, dfra = 1.0, frs_sec = G.scene->r.frs_sec; + float t, time = 0.0, keytime = 0.0, dfra = 1.0, frs_sec = G.scene->r.frs_sec; float col[3] = {0.5f, 0.5f, 0.5f}; float prev_tangent[3], hairmat[4][4]; int k,i; @@ -2227,6 +2335,10 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda char nosel[4], sel[4]; float sel_col[3]; float nosel_col[3]; + 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]; /* 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) @@ -2260,21 +2372,28 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda else { /* clear out old and create new empty path cache */ psys_free_path_cache(psys); - - /* allocate cache array for fast access and set pointers to contiguous mem block */ - cache = psys->pathcache = MEM_callocN(MAX2(1, totpart) * sizeof(void *), "Path cache array"); - cache[0] = MEM_callocN(totpart * (steps + 1) * sizeof(ParticleCacheKey), "Path cache"); - for(i=1; i<totpart; i++) - cache[i] = cache[0] + i * (steps + 1); + cache= psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, steps+1); + psys->pathcache= cache; } - if(edit==NULL && psys->soft && psys->softflag & OB_SB_ENABLE) + if(edit==NULL && psys->soft && psys->softflag & OB_SB_ENABLE) { soft = psys->soft; + if(!soft->bpoint) + soft= NULL; + } psys->lattice = psys_get_lattice(ob, psys); ma= give_current_material(ob, psys->part->omat); if(ma && (psys->part->draw & PART_DRAW_MAT_COL)) VECCOPY(col, &ma->r) + + if(psys->part->from!=PART_FROM_PARTICLE) { + if(!(psys->part->flag & PART_CHILD_EFFECT)) + vg_effector = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_EFFECTOR); + + if(!edit && !psys->totchild) + vg_length = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_LENGTH); + } /*---first main loop: create all actual particles' paths---*/ for(i=0,pa=psys->particles; i<totpart; i++, pa++){ @@ -2287,6 +2406,12 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda if(editupdate && !(pa->flag & PARS_EDIT_RECALC)) continue; 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]); + if(vg_length) + pa_length *= psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_length); + } + cache[i]->steps = steps; if(edit) @@ -2368,7 +2493,7 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda if(soft) { if(hkey[1] != pa->hair + pa->totkey - 1) - bp_to_particle(keys + 3, bp[1], hkey[1] + 1); + bp_to_particle(keys + 3, bp[1] + 1, hkey[1] + 1); else bp_to_particle(keys + 3, bp[1], hkey[1]); } @@ -2393,8 +2518,7 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda /* 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)*/ interpolate_particle((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic interpolation */ : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL) - ,keys, keytime, &result); - + ,keys, keytime, &result, 0); /* the velocity needs to be converted back from cubic interpolation */ if(psys->flag & PSYS_KEYED){ @@ -2403,38 +2527,92 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda else if(soft==NULL) { /* softbody and keyed are allready in global space */ Mat4MulVecfl(hairmat, result.co); } - + + VECCOPY(ca->co, result.co); + + /* selection coloring in edit mode */ + if(edit){ + if(pset->brushtype==PE_BRUSH_WEIGHT){ + if(k==steps) + VecLerpf(ca->col, nosel_col, sel_col, hkey[0]->weight); + else + VecLerpf(ca->col, nosel_col, sel_col, + (1.0f - keytime) * hkey[0]->weight + keytime * hkey[1]->weight); + } + else{ + if((ekey + (hkey[0] - pa->hair))->flag & PEK_SELECT){ + if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){ + VECCOPY(ca->col, sel_col); + } + else{ + VecLerpf(ca->col, sel_col, nosel_col, keytime); + } + } + else{ + if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){ + VecLerpf(ca->col, nosel_col, sel_col, keytime); + } + else{ + VECCOPY(ca->col, nosel_col); + } + } + } + } + else{ + VECCOPY(ca->col, col); + } + } + + /*--modify paths--*/ + + VecSubf(vec,(cache[i]+1)->co,cache[i]->co); + length = VecLength(vec); + + effector= 1.0f; + if(vg_effector) + effector*= psys_particle_value_from_verts(psmd->dm,psys->part->from,pa,vg_effector); + + for(k=0, ca=cache[i]; k<=steps; k++, ca++) { + /* apply effectors */ + if(!(psys->part->flag & PART_CHILD_EFFECT) && edit==0 && k) + do_path_effectors(ob, psys, i, ca, k, steps, cache[i]->co, effector, dfra, cfra, &length, vec); /* apply guide curves to path data */ - if(edit==0 && psys->effectors.first && (psys->part->flag & PART_CHILD_GUIDE)==0) - do_guide(&result, i, time, &psys->effectors); + if(edit==0 && psys->effectors.first && (psys->part->flag & PART_CHILD_EFFECT)==0) + /* ca is safe to cast, since only co and vel are used */ + do_guide((ParticleKey*)ca, i, (float)k/(float)steps, &psys->effectors); + + /* apply lattice */ + if(psys->lattice && edit==0) + calc_latt_deform(ca->co, 1.0f); /* figure out rotation */ if(k) { - float angle, tangent[3], normal[3], q[4]; + float cosangle, angle, tangent[3], normal[3], q[4]; if(k == 1) { - float *q2; - - VECSUB(tangent, result.co, (ca - 1)->co); + VECSUB(tangent, ca->co, (ca - 1)->co); - q2 = vectoquat(tangent, OB_POSX, OB_POSZ); - - QUATCOPY((ca - 1)->rot, q2); + vectoquat(tangent, OB_POSX, OB_POSZ, (ca-1)->rot); VECCOPY(prev_tangent, tangent); Normalize(prev_tangent); } else { - VECSUB(tangent, result.co, (ca - 1)->co); + VECSUB(tangent, ca->co, (ca - 1)->co); Normalize(tangent); - angle = saacos(Inpf(tangent, prev_tangent)); - if((angle > -0.000001) && (angle < 0.000001)){ + cosangle= Inpf(tangent, prev_tangent); + + /* note we do the comparison on cosangle instead of + * angle, since floating point accuracy makes it give + * different results across platforms */ + if(cosangle > 0.999999f) { QUATCOPY((ca - 1)->rot, (ca - 2)->rot); } - else{ + else { + angle= saacos(cosangle); Crossf(normal, prev_tangent, tangent); VecRotToQuat(normal, angle, q); QuatMul((ca - 1)->rot, q, (ca - 2)->rot); @@ -2443,13 +2621,13 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda VECCOPY(prev_tangent, tangent); } - if(k == steps) { + if(k == steps) QUATCOPY(ca->rot, (ca - 1)->rot); - } } - VECCOPY(ca->co, result.co); + /* set velocity */ + if(k){ VECSUB(ca->vel, ca->co, (ca-1)->co); @@ -2459,40 +2637,27 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda } - /* selection coloring in edit mode */ - if(edit){ - if(pset->brushtype==PE_BRUSH_WEIGHT){ - if(k==steps) - VecLerpf(ca->col, nosel_col, sel_col, hkey[0]->weight); + 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 - VecLerpf(ca->col,nosel_col,sel_col, - (1.0f - keytime) * hkey[0]->weight + keytime * hkey[1]->weight); + len=1.0f/(float)steps; + + k=check_path_length(k,cache[i],ca,max_length,&cur_length,len,dvec); } else{ - if((ekey + (hkey[0] - pa->hair))->flag & PEK_SELECT){ - if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){ - VECCOPY(ca->col, sel_col); - } - else{ - VecLerpf(ca->col, sel_col, nosel_col, keytime); - } - } - else{ - if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){ - VecLerpf(ca->col, nosel_col, sel_col, keytime); - } - else{ - VECCOPY(ca->col, nosel_col); - } - } + /* initialize length calculation */ + if(part->flag&PART_ABS_LENGTH) + max_length= part->abslength*pa_length; + else + max_length= pa_length; + + cur_length= 0.0f; } } - else{ - VECCOPY(ca->col, col); - } - - if(psys->lattice && edit==0) - calc_latt_deform(ca->co, 1.0f); } } @@ -2502,6 +2667,12 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda end_latt_deform(); psys->lattice=0; } + + if(vg_effector) + MEM_freeN(vg_effector); + + if(vg_length) + MEM_freeN(vg_length); } /************************************************/ /* Particle Key handling */ @@ -2640,7 +2811,7 @@ void psys_mat_hair_to_object(Object *ob, DerivedMesh *dm, short from, ParticleDa float vec[3]; psys_face_mat(0, dm, pa, hairmat, 0); - psys_particle_on_dm(ob, dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0, 0); + psys_particle_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0, 0); VECCOPY(hairmat[3],vec); } @@ -2649,62 +2820,14 @@ void psys_mat_hair_to_orco(Object *ob, DerivedMesh *dm, short from, ParticleData float vec[3], orco[3]; psys_face_mat(ob, dm, pa, hairmat, 1); - psys_particle_on_dm(ob, dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, orco, 0); + psys_particle_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, orco, 0); /* see psys_face_mat for why this function is called */ transform_mesh_orco_verts(ob->data, &orco, 1, 1); VECCOPY(hairmat[3],orco); } -/* -void psys_key_to_geometry(DerivedMesh *dm, ParticleData *pa, ParticleKey *key) -{ - float q[4], v1[3], v2[3], v3[3]; - - dm->getVertCo(dm,pa->verts[0],v1); - dm->getVertCo(dm,pa->verts[1],v2); - dm->getVertCo(dm,pa->verts[2],v3); - - triatoquat(v1, v2, v3, q); - - QuatInv(q); - - VECSUB(key->co,key->co,v1); - - VECADD(key->vel,key->vel,key->co); - - QuatMulVecf(q, key->co); - QuatMulVecf(q, key->vel); - - VECSUB(key->vel,key->vel,key->co); - - QuatMul(key->rot,q,key->rot); -} - -void psys_key_from_geometry(DerivedMesh *dm, ParticleData *pa, ParticleKey *key) -{ - float q[4], v1[3], v2[3], v3[3]; - - dm->getVertCo(dm,pa->verts[0],v1); - dm->getVertCo(dm,pa->verts[1],v2); - dm->getVertCo(dm,pa->verts[2],v3); - - triatoquat(v1, v2, v3, q); - - VECADD(key->vel,key->vel,key->co); - - QuatMulVecf(q, key->co); - QuatMulVecf(q, key->vel); - - VECSUB(key->vel,key->vel,key->co); - - VECADD(key->co,key->co,v1); - - QuatMul(key->rot,q,key->rot); -} -*/ - -void psys_vec_rot_to_face(DerivedMesh *dm, ParticleData *pa, float *vec)//to_geometry(DerivedMesh *dm, ParticleData *pa, float *vec) +void psys_vec_rot_to_face(DerivedMesh *dm, ParticleData *pa, float *vec) { float mat[4][4]; @@ -2713,36 +2836,6 @@ void psys_vec_rot_to_face(DerivedMesh *dm, ParticleData *pa, float *vec)//to_geo Mat4Mul3Vecfl(mat, vec); } -/* unused */ -#if 0 -static void psys_vec_rot_from_face(DerivedMesh *dm, ParticleData *pa, float *vec)//from_geometry(DerivedMesh *dm, ParticleData *pa, float *vec) -{ - float q[4], v1[3], v2[3], v3[3]; - /* - dm->getVertCo(dm,pa->verts[0],v1); - dm->getVertCo(dm,pa->verts[1],v2); - dm->getVertCo(dm,pa->verts[2],v3); - */ - /* replace with this */ - MFace *mface; - int i; // = psys_particle_dm_face_lookup(dm, pa->num, pa->fuv, pa->foffset, (LinkNode*)NULL); - i = pa->num_dmcache==DMCACHE_NOTFOUND ? pa->num : pa->num_dmcache; - if (i==-1 || i >= dm->getNumFaces(dm)) { vec[0] = vec[1] = 0; vec[2] = 1; return; } - mface=dm->getFaceData(dm,i,CD_MFACE); - - dm->getVertCo(dm,mface->v1,v1); - dm->getVertCo(dm,mface->v2,v2); - dm->getVertCo(dm,mface->v3,v3); - /* done */ - - triatoquat(v1, v2, v3, q); - - QuatMulVecf(q, vec); - - //VECADD(vec,vec,v1); -} -#endif - void psys_mat_hair_to_global(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[][4]) { float facemat[4][4]; @@ -2779,10 +2872,10 @@ static void default_particle_settings(ParticleSettings *part) part->integrator= PART_INT_MIDPOINT; part->phystype= PART_PHYS_NEWTON; - part->hair_step= 10; + part->hair_step= 5; part->keys_step= 5; - part->draw_step= 4; - part->ren_step= 6; + part->draw_step= 2; + part->ren_step= 3; part->adapt_angle= 5; part->adapt_pix= 3; part->kink_axis= 2; @@ -2790,7 +2883,6 @@ static void default_particle_settings(ParticleSettings *part) part->disp=100; part->from= PART_FROM_FACE; part->length= 1.0; - part->rotfac= 1.0; part->nbetween= 4; part->boidneighbours= 5; @@ -2853,11 +2945,12 @@ ParticleSettings *psys_copy_settings(ParticleSettings *part) partn= copy_libblock(part); if(partn->pd) partn->pd= MEM_dupallocN(part->pd); + if(partn->pd2) partn->pd2= MEM_dupallocN(part->pd2); return partn; } -void psys_make_local_settings(ParticleSettings *part) +void make_local_particlesettings(ParticleSettings *part) { Object *ob; ParticleSettings *par; @@ -2943,7 +3036,7 @@ void psys_flush_settings(ParticleSettings *part, int event, int hair_recalc) tpsys=BLI_findlink(&tob->particlesystem,psys->target_psys-1); if(tpsys && tpsys->part==part){ - psys->flag |= event; + psys->recalc |= event; flush++; } } @@ -2953,9 +3046,86 @@ void psys_flush_settings(ParticleSettings *part, int event, int hair_recalc) } } } + +LinkNode *psys_using_settings(ParticleSettings *part, int flush_update) +{ + Object *ob, *tob; + ParticleSystem *psys, *tpsys; + LinkNode *node= NULL; + int found; + + /* update all that have same particle settings */ + for(ob=G.main->object.first; ob; ob=ob->id.next) { + found= 0; + + for(psys=ob->particlesystem.first; psys; psys=psys->next) { + if(psys->part == part) { + BLI_linklist_append(&node, psys); + found++; + } + else if(psys->part->type == PART_REACTOR){ + tob= (psys->target_ob)? psys->target_ob: ob; + tpsys= BLI_findlink(&tob->particlesystem, psys->target_psys-1); + + if(tpsys && tpsys->part==part) { + BLI_linklist_append(&node, tpsys); + found++; + } + } + } + + if(flush_update && found) + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + } + + return node; +} + + /************************************************/ /* Textures */ /************************************************/ + +static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, float *fuv, char *name, float *texco) +{ + MFace *mf; + MTFace *tf; + int i; + + tf= CustomData_get_layer_named(&dm->faceData, CD_MTFACE, name); + + if(tf == NULL) + tf= CustomData_get_layer(&dm->faceData, CD_MTFACE); + + if(tf == NULL) + return 0; + + if(pa) { + i= (pa->num_dmcache==DMCACHE_NOTFOUND)? pa->num: pa->num_dmcache; + if(i >= dm->getNumFaces(dm)) + i = -1; + } + else + i= face_index; + + if (i==-1) { + texco[0]= 0.0f; + texco[1]= 0.0f; + texco[2]= 0.0f; + } + else { + mf= dm->getFaceData(dm, i, CD_MFACE); + + psys_interpolate_uvs(&tf[i], mf->v4, fuv, texco); + + texco[0]= texco[0]*2.0f - 1.0f; + texco[1]= texco[1]*2.0f - 1.0f; + texco[2]= 0.0f; + } + + return 1; +} + static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float *fw, float *orco, ParticleTexture *ptex, int event) { MTex *mtex; @@ -2965,31 +3135,18 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float if(ma) for(m=0; m<MAX_MTEX; m++){ mtex=ma->mtex[m]; if(mtex && (ma->septex & (1<<m))==0){ + float def=mtex->def_var; float var=mtex->varfac; short blend=mtex->blendtype; short neg=mtex->pmaptoneg; - if(mtex->texco & TEXCO_UV && fw){ - int uv_index=CustomData_get_named_layer_index(&dm->faceData,CD_MTFACE,mtex->uvname); - if(uv_index<0){ - uv_index=CustomData_get_active_layer_index(&dm->faceData,CD_MTFACE); - } - if(uv_index>=0){ - CustomDataLayer *layer=&dm->faceData.layers[uv_index]; - MTFace *mtface= &((MTFace*)layer->data)[face_index]; - MFace *mf=dm->getFaceData(dm,face_index,CD_MFACE); - psys_interpolate_uvs(mtface,mf->v4,fw,texco); - texco[0]*=2.0; - texco[1]*=2.0; - texco[0]-=1.0; - texco[1]-=1.0; - } - else + if((mtex->texco & TEXCO_UV) && fw) { + if(!get_particle_uv(dm, NULL, face_index, fw, mtex->uvname, texco)) VECCOPY(texco,orco); } - else{ + else VECCOPY(texco,orco); - } + externtex(mtex, texco, &value, rgba, rgba+1, rgba+2, rgba+3); if((event & mtex->pmapto) & MAP_PA_TIME){ if((setvars&MAP_PA_TIME)==0){ @@ -2999,13 +3156,13 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float ptex->time= texture_value_blend(mtex->def_var,ptex->time,value,var,blend,neg & MAP_PA_TIME); } if((event & mtex->pmapto) & MAP_PA_LENGTH) - ptex->length= texture_value_blend(value,ptex->length,value,var,blend,neg & MAP_PA_LENGTH); + ptex->length= texture_value_blend(def,ptex->length,value,var,blend,neg & MAP_PA_LENGTH); if((event & mtex->pmapto) & MAP_PA_CLUMP) - ptex->clump= texture_value_blend(value,ptex->clump,value,var,blend,neg & MAP_PA_CLUMP); + ptex->clump= texture_value_blend(def,ptex->clump,value,var,blend,neg & MAP_PA_CLUMP); if((event & mtex->pmapto) & MAP_PA_KINK) - ptex->kink= texture_value_blend(value,ptex->kink,value,var,blend,neg & 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(value,ptex->rough,value,var,blend,neg & MAP_PA_ROUGH); + ptex->rough= texture_value_blend(def,ptex->rough,value,var,blend,neg & MAP_PA_ROUGH); } } if(event & MAP_PA_TIME) { CLAMP(ptex->time,0.0,1.0); } @@ -3025,61 +3182,48 @@ void psys_get_texture(Object *ob, Material *ma, ParticleSystemModifierData *psmd mtex=ma->mtex[m]; if(mtex && (ma->septex & (1<<m))==0){ float var=mtex->varfac; + float def=mtex->def_var; short blend=mtex->blendtype; short neg=mtex->pmaptoneg; - if(mtex->texco & TEXCO_UV){ - int uv_index=CustomData_get_named_layer_index(&psmd->dm->faceData,CD_MTFACE,mtex->uvname); - if(uv_index<0){ - uv_index=CustomData_get_active_layer_index(&psmd->dm->faceData,CD_MTFACE); - } - if(uv_index>=0){ - CustomDataLayer *layer=&psmd->dm->faceData.layers[uv_index]; - MTFace *mtface= &((MTFace*)layer->data)[pa->num]; - MFace *mf=psmd->dm->getFaceData(psmd->dm,pa->num,CD_MFACE); - psys_interpolate_uvs(mtface,mf->v4,pa->fuv,texco); - texco[0]*=2.0; - texco[1]*=2.0; - texco[0]-=1.0; - texco[1]-=1.0; + if((mtex->texco & TEXCO_UV) && ELEM(psys->part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { + if(!get_particle_uv(psmd->dm, pa, 0, pa->fuv, mtex->uvname, texco)) { + /* failed to get uv's, let's try orco's */ + psys_particle_on_emitter(psmd,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,0,0,0,texco, 0); } - else - //psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,pa->fuv,pa->foffset,texco,0,0,0); - /* <jahka> anyways I think it will be too small a difference to notice, so psys_get_texture should only know about the original mesh structure.. no dm needed anywhere */ - /* <brecht> the code only does dm based lookup now, so passing num_dmcache anyway to avoid^ - * massive slowdown here */ - psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,0,0,0,texco, 0); } - else{ - //psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,pa->fuv,pa->offset,texco,0,0,0); - /* ditto above */ - psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,0,0,0,texco, 0); + else { + psys_particle_on_emitter(psmd,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,0,0,0,texco, 0); } + externtex(mtex, texco, &value, rgba, rgba+1, rgba+2, rgba+3); if((event & mtex->pmapto) & MAP_PA_TIME){ + /* the first time has to set the base value for time regardless of blend mode */ if((setvars&MAP_PA_TIME)==0){ - ptex->time=0.0; - setvars|=MAP_PA_TIME; + ptex->time *= 1.0f - var; + ptex->time += var * ((neg & MAP_PA_TIME)? 1.0f - value : value); + setvars |= MAP_PA_TIME; } - ptex->time= texture_value_blend(mtex->def_var,ptex->time,value,var,blend,neg & MAP_PA_TIME); + else + ptex->time= texture_value_blend(def,ptex->time,value,var,blend,neg & MAP_PA_TIME); } if((event & mtex->pmapto) & MAP_PA_LIFE) - ptex->life= texture_value_blend(mtex->def_var,ptex->life,value,var,blend,neg & MAP_PA_LIFE); + ptex->life= texture_value_blend(def,ptex->life,value,var,blend,neg & MAP_PA_LIFE); if((event & mtex->pmapto) & MAP_PA_DENS) - ptex->exist= texture_value_blend(mtex->def_var,ptex->exist,value,var,blend,neg & MAP_PA_DENS); + ptex->exist= texture_value_blend(def,ptex->exist,value,var,blend,neg & MAP_PA_DENS); if((event & mtex->pmapto) & MAP_PA_SIZE) - ptex->size= texture_value_blend(mtex->def_var,ptex->size,value,var,blend,neg & MAP_PA_SIZE); + ptex->size= texture_value_blend(def,ptex->size,value,var,blend,neg & MAP_PA_SIZE); if((event & mtex->pmapto) & MAP_PA_IVEL) - ptex->ivel= texture_value_blend(mtex->def_var,ptex->ivel,value,var,blend,neg & MAP_PA_IVEL); + ptex->ivel= texture_value_blend(def,ptex->ivel,value,var,blend,neg & MAP_PA_IVEL); if((event & mtex->pmapto) & MAP_PA_PVEL) texture_rgb_blend(ptex->pvel,rgba,ptex->pvel,value,var,blend); if((event & mtex->pmapto) & MAP_PA_LENGTH) - ptex->length= texture_value_blend(mtex->def_var,ptex->length,value,var,blend,neg & MAP_PA_LENGTH); + ptex->length= texture_value_blend(def,ptex->length,value,var,blend,neg & MAP_PA_LENGTH); if((event & mtex->pmapto) & MAP_PA_CLUMP) - ptex->clump= texture_value_blend(mtex->def_var,ptex->clump,value,var,blend,neg & MAP_PA_CLUMP); + ptex->clump= texture_value_blend(def,ptex->clump,value,var,blend,neg & MAP_PA_CLUMP); if((event & mtex->pmapto) & MAP_PA_KINK) - ptex->kink= texture_value_blend(mtex->def_var,ptex->kink,value,var,blend,neg & MAP_PA_CLUMP); + ptex->kink= texture_value_blend(def,ptex->kink,value,var,blend,neg & MAP_PA_CLUMP); } } if(event & MAP_PA_TIME) { CLAMP(ptex->time,0.0,1.0); } @@ -3116,7 +3260,7 @@ float psys_get_size(Object *ob, Material *ma, ParticleSystemModifierData *psmd, } if(vg_size) - size*=psys_interpolate_value_from_verts(psmd->dm,part->from,pa->num,pa->fuv,vg_size); + size*=psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_size); if(part->randsize!=0.0) size*= 1.0f - part->randsize*pa->sizemul; @@ -3149,16 +3293,24 @@ float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra, float size, time; if(part->childtype==PART_CHILD_FACES){ - if(pa_time) - time=*pa_time; - else - time=psys_get_child_time(psys,cpa,cfra); + size=part->size; if((part->flag&PART_ABS_TIME)==0 && part->ipo){ + IpoCurve *icu; + + if(pa_time) + time=*pa_time; + else + time=psys_get_child_time(psys,cpa,cfra); + + /* correction for lifetime */ calc_ipo(part->ipo, 100*time); - execute_ipo((ID *)part, part->ipo); + + for(icu = part->ipo->curve.first; icu; icu=icu->next) { + if(icu->adrcode == PART_SIZE) + size = icu->curval; + } } - size=part->size; } else size=psys->particles[cpa->parent].size; @@ -3179,13 +3331,13 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle ParticleData *pa; ChildParticle *cpa; ParticleTexture ptex; - ParticleKey tstate; - HairKey *hkey[2]; + ParticleKey *kkey[2] = {NULL, NULL}; + HairKey *hkey[2] = {NULL, NULL}; ParticleKey *par=0, keys[4]; - float t, real_t, dfra, keytime; + float t, real_t, dfra, keytime, frs_sec = G.scene->r.frs_sec; float co[3], orco[3]; - float imat[4][4], hairmat[4][4], cpa_1st[3]; + float hairmat[4][4]; float pa_clump = 0.0, pa_kink = 0.0; int totparent = 0; int totpart = psys->totpart; @@ -3218,19 +3370,39 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle return; } - hkey[0] = pa->hair; - hkey[1] = pa->hair + 1; + if(psys->flag & PSYS_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); + } + 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; + real_t = hkey[0]->time + (hkey[0][pa->totkey-1].time - hkey[0]->time) * t; + } - while(hkey[1]->time < real_t) - hkey[1]++; + if(psys->flag & PSYS_KEYED) { + while(kkey[1]->time < real_t) { + kkey[1]++; + } + kkey[0] = kkey[1] - 1; - hkey[0] = hkey[1] - 1; + memcpy(keys + 1, kkey[0], sizeof(ParticleKey)); + memcpy(keys + 2, kkey[1], sizeof(ParticleKey)); + } + else { + while(hkey[1]->time < real_t) + hkey[1]++; - hair_to_particle(keys + 1, hkey[0]); - hair_to_particle(keys + 2, hkey[1]); + hkey[0] = hkey[1] - 1; + hair_to_particle(keys + 1, hkey[0]); + 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); @@ -3255,6 +3427,7 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle hair_to_particle(keys + 3, hkey[1] + 1); else hair_to_particle(keys + 3, hkey[1]); + } //} //psys_get_particle_on_path(bsys,p,t,bkey,ckey[0]); @@ -3264,35 +3437,48 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle //else{ // /* TODO: different rotations */ // float nvel[3]; - // float *q2; // VECCOPY(nvel,state->vel); // VecMulf(nvel,-1.0f); - // q2=vectoquat(nvel, OB_POSX, OB_POSZ); - // QUATCOPY(state->rot,q2); + // vectoquat(nvel, OB_POSX, OB_POSZ, state->rot); //} dfra = keys[2].time - keys[1].time; keytime = (real_t - keys[1].time) / dfra; - interpolate_particle((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL - ,keys, keytime, state); + /* convert velocity to timestep size */ + if(psys->flag & PSYS_KEYED){ + VecMulf(keys[1].vel, dfra / frs_sec); + VecMulf(keys[2].vel, dfra / frs_sec); + QuatInterpol(state->rot,keys[1].rot,keys[2].rot,keytime); + } - if((pa->flag & PARS_REKEY)==0) { - psys_mat_hair_to_global(ob, psmd->dm, part->from, pa, hairmat); - Mat4MulVecfl(hairmat, state->co); + interpolate_particle((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic interpolation */ + : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL) + ,keys, keytime, state, 1); - if(psys->effectors.first && (part->flag & PART_CHILD_GUIDE)==0) { - do_guide(state, p, state->time, &psys->effectors); - /* TODO: proper velocity handling */ - } + /* the velocity needs to be converted back from cubic interpolation */ + if(psys->flag & PSYS_KEYED){ + VecMulf(state->vel, frs_sec / dfra); + } + else { + if((pa->flag & PARS_REKEY)==0) { + psys_mat_hair_to_global(ob, psmd->dm, part->from, pa, hairmat); + Mat4MulVecfl(hairmat, state->co); + Mat4Mul3Vecfl(hairmat, state->vel); + + if(psys->effectors.first && (part->flag & PART_CHILD_GUIDE)==0) { + do_guide(state, p, state->time, &psys->effectors); + /* TODO: proper velocity handling */ + } - if(psys->lattice && edit==0) - calc_latt_deform(state->co,1.0f); + if(psys->lattice && edit==0) + calc_latt_deform(state->co,1.0f); + } } } else if(totchild){ - Mat4Invert(imat,ob->obmat); + //Mat4Invert(imat,ob->obmat); cpa=psys->child+p-totpart; @@ -3321,22 +3507,12 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle cpa_fuv = cpa->fuv; cpa_from = PART_FROM_FACE; - psys_particle_on_emitter(ob,psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,co,0,0,0,orco,0); + psys_particle_on_emitter(psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,co,0,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); - - //w=0; - //while(w<4 && cpa->pa[w]>=0){ - // pa=psys->particles+cpa->pa[w]; - // psys_particle_on_emitter(ob,psmd,part->from,pa->num,pa->fuv,pa->foffset,vec,0,0,0); - // cpa_1st[0] -= cpa->w[w]*vec[0]; - // cpa_1st[1] -= cpa->w[w]*vec[1]; - // cpa_1st[2] -= cpa->w[w]*vec[2]; - // w++; - //} + //VECCOPY(cpa_1st,co); - Mat4MulVecfl(ob->obmat,cpa_1st); + //Mat4MulVecfl(ob->obmat,cpa_1st); pa=0; } @@ -3353,7 +3529,7 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle cpa_num=pa->num; cpa_fuv=pa->fuv; - psys_particle_on_emitter(ob,psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,0,0,0,orco,0); + psys_particle_on_emitter(psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,0,0,0,orco,0); } /* correct child ipo timing */ @@ -3391,7 +3567,7 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle w++; } /* apply offset for correct positioning */ - VECADD(state->co,state->co,cpa_1st); + //VECADD(state->co,state->co,cpa_1st); } else{ /* offset the child from the parent position */ @@ -3418,12 +3594,8 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle do_clump(state, par, t, part->clumpfac, part->clumppow, 1.0f); - if(part->kink) - do_postkink(state, par, par->rot, t, part->kink_freq * pa_kink, part->kink_shape, - part->kink_amp, part->kink, part->kink_axis, ob->obmat); - if(part->rough1 != 0.0) - do_rough(orco, t, part->rough1, part->rough1_size, 0.0, state); + do_rough(orco, t, part->rough1, part->rough1_size, 0.0, state); if(part->rough2 != 0.0) do_rough(cpa->rand, t, part->rough2, part->rough2_size, part->rough2_thres, state); @@ -3431,19 +3603,18 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle 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(ob,psys,p,&tstate,0); - VECSUB(state->vel,state->co,tstate.co); - } - else{ - tstate.time=t+0.001f; - psys_get_particle_on_path(ob,psys,p,&tstate,0); - VECSUB(state->vel,tstate.co,state->co); - } - } - + //if(vel){ + // if(t>=0.001f){ + // tstate.time=t-0.001f; + // psys_get_particle_on_path(ob,psys,p,&tstate,0); + // VECSUB(state->vel,state->co,tstate.co); + // } + // else{ + // tstate.time=t+0.001f; + // psys_get_particle_on_path(ob,psys,p,&tstate,0); + // VECSUB(state->vel,tstate.co,state->co); + // } + //} } } /* gets particle's state at a time, returns 1 if particle exists and can be seen and 0 if not */ @@ -3453,6 +3624,7 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey float cfra; int totpart=psys->totpart, between=0; + /* negative time means "use current time" */ if(state->time>0) cfra=state->time; else @@ -3484,50 +3656,92 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey return 0; } - //if(bsys->flag & (BSYS_DONE|BSYS_KEYED)){ - // if(between){ - // //ChildParticle *cpa=psys->child+p-totpart; - // //state->time= (cfra-(part->sta+(part->end-part->sta)*cpa->rand[0]))/(part->lifetime*cpa->rand[1]); - // } - // else - // state->time= (cfra-pa->time)/(pa->dietime-pa->time);//pa->lifetime; + if(psys->flag & PSYS_KEYED){ + if(between){ + ChildParticle *cpa=psys->child+p-totpart; + state->time= (cfra-(part->sta+(part->end-part->sta)*cpa->rand[0]))/(part->lifetime*cpa->rand[1]); + } + else + state->time= (cfra-pa->time)/(pa->dietime-pa->time); - // psys_get_particle_on_path(ob,psys,p,state,1); - // return 1; - //} - //else{ - //if(psys->totchild && p>=psys->totpart){ - // ChildParticle *cpa=psys->child+p-psys->totpart; - // ParticleKey *key1, skey; - // float t=(cfra-pa->time)/pa->lifetime, clump; - - // pa=psys->particles+cpa->parent; - - // if(pa->alive==PARS_DEAD && part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob){ - // key1=&skey; - // copy_particle_key(key1,&pa->state,0); - // key_from_object(pa->stick_ob,key1); - // } - // else{ - // key1=&pa->state; - // } - // - // offset_child(cpa, key1, state, part->childflat, part->childrad); - // - // CLAMP(t,0.0,1.0); - // if(part->kink) /* TODO: part->kink_freq*pa_kink */ - // do_prekink(state,key1,t,part->kink_freq,part->kink_shape,part->kink_amp,part->kink,part->kink_axis,ob->obmat); - // - // /* TODO: pa_clump vgroup */ - // do_clump(state,key1,t,part->clumpfac,part->clumppow,0); - - // if(part->kink) /* TODO: part->kink_freq*pa_kink */ - // do_postkink(state,key1,t,part->kink_freq,part->kink_shape,part->kink_amp,part->kink,part->kink_axis,ob->obmat); + psys_get_particle_on_path(ob,psys,p,state,1); + return 1; + } + else{ + if(between) + return 0; /* currently not supported */ + else if(psys->totchild && p>=psys->totpart){ + ChildParticle *cpa=psys->child+p-psys->totpart; + ParticleKey *key1, skey; + float t = (cfra - pa->time + pa->loop * pa->lifetime) / pa->lifetime; + + pa = psys->particles + cpa->parent; + + if(pa->alive==PARS_DEAD && part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob) { + key1 = &skey; + copy_particle_key(key1,&pa->state,0); + key_from_object(pa->stick_ob,key1); + } + else { + key1=&pa->state; + } + + offset_child(cpa, key1, state, part->childflat, part->childrad); + + CLAMP(t,0.0,1.0); + if(part->kink) /* TODO: part->kink_freq*pa_kink */ + do_prekink(state,key1,key1->rot,t,part->kink_freq,part->kink_shape,part->kink_amp,part->kink,part->kink_axis,ob->obmat); + + /* TODO: pa_clump vgroup */ + do_clump(state,key1,t,part->clumpfac,part->clumppow,1.0); - //} - //else{ + if(psys->lattice) + calc_latt_deform(state->co,1.0f); + } + else{ if (pa) { /* TODO PARTICLE - should this ever be NULL? - Campbell */ - copy_particle_key(state,&pa->state,0); + if(pa->state.time==state->time || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED)) + copy_particle_key(state, &pa->state, 1); + else if(pa->prev_state.time==state->time) + copy_particle_key(state, &pa->prev_state, 1); + else { + /* let's interpolate to try to be as accurate as possible */ + if(pa->state.time + 1.0f > state->time && pa->prev_state.time - 1.0f < state->time) { + ParticleKey keys[4]; + float dfra, keytime, frs_sec = G.scene->r.frs_sec; + + if(pa->prev_state.time >= pa->state.time) { + /* prev_state is wrong so let's not use it, this can happen at frame 1 or particle birth */ + copy_particle_key(state, &pa->state, 1); + + VECADDFAC(state->co, state->co, state->vel, (state->time-pa->state.time)/frs_sec); + } + else { + copy_particle_key(keys+1, &pa->prev_state, 1); + copy_particle_key(keys+2, &pa->state, 1); + + dfra = keys[2].time - keys[1].time; + + keytime = (state->time - keys[1].time) / dfra; + + /* convert velocity to timestep size */ + VecMulf(keys[1].vel, dfra / frs_sec); + VecMulf(keys[2].vel, dfra / frs_sec); + + interpolate_particle(-1, keys, keytime, state, 1); + + /* convert back to real velocity */ + VecMulf(state->vel, frs_sec / dfra); + + VecLerpf(state->ave, keys[1].ave, keys[2].ave, keytime); + QuatInterpol(state->rot, keys[1].rot, keys[2].rot, keytime); + } + } + else { + /* extrapolating over big ranges is not accurate so let's just give something close to reasonable back */ + copy_particle_key(state, &pa->state, 0); + } + } if(pa->alive==PARS_DEAD && part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob){ key_from_object(pa->stick_ob,state); @@ -3536,9 +3750,111 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey if(psys->lattice) calc_latt_deform(state->co,1.0f); } - //} + } return 1; - //} + } +} + +void psys_get_dupli_texture(Object *ob, ParticleSettings *part, ParticleSystemModifierData *psmd, ParticleData *pa, ChildParticle *cpa, float *uv, float *orco) +{ + MFace *mface; + MTFace *mtface; + float loc[3]; + int num; + + if(cpa) { + if(part->childtype == PART_CHILD_FACES) { + mtface= CustomData_get_layer(&psmd->dm->faceData, CD_MTFACE); + if(mtface) { + mface= psmd->dm->getFaceData(psmd->dm, cpa->num, CD_MFACE); + mtface += cpa->num; + psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv); + } + else + uv[0]= uv[1]= 0.0f; + } + else + uv[0]= uv[1]= 0.0f; + + psys_particle_on_emitter(psmd, + (part->childtype == PART_CHILD_FACES)? PART_FROM_FACE: PART_FROM_PARTICLE, + cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,loc,0,0,0,orco,0); + } + else { + if(part->from == PART_FROM_FACE) { + mtface= CustomData_get_layer(&psmd->dm->faceData, CD_MTFACE); + num= pa->num_dmcache; + + if(num == DMCACHE_NOTFOUND) + if(pa->num < psmd->dm->getNumFaces(psmd->dm)) + num= pa->num; + + if(mtface && num != DMCACHE_NOTFOUND) { + mface= psmd->dm->getFaceData(psmd->dm, num, CD_MFACE); + mtface += num; + psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv); + } + else + uv[0]= uv[1]= 0.0f; + } + else + uv[0]= uv[1]= 0.0f; + + psys_particle_on_emitter(psmd,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,0,0,0,orco,0); + } +} + +void psys_get_dupli_path_transform(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[][4], float *scale) +{ + float loc[3], nor[3], vec[3], side[3], len, obrotmat[4][4], qmat[4][4]; + float xvec[3] = {-1.0, 0.0, 0.0}, q[4]; + + VecSubf(vec, (cache+cache->steps-1)->co, cache->co); + len= Normalize(vec); + + if(pa) + psys_particle_on_emitter(psmd,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,nor,0,0,0,0); + else + psys_particle_on_emitter(psmd, + (psys->part->childtype == PART_CHILD_FACES)? PART_FROM_FACE: PART_FROM_PARTICLE, + cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,loc,nor,0,0,0,0); + + if(psys->part->rotmode) { + if(!pa) + pa= psys->particles+cpa->pa[0]; + + vectoquat(xvec, ob->trackflag, ob->upflag, q); + QuatToMat4(q, obrotmat); + obrotmat[3][3]= 1.0f; + + QuatToMat4(pa->state.rot, qmat); + Mat4MulMat4(mat, obrotmat, qmat); + } + else { + /* make sure that we get a proper side vector */ + if(fabs(Inpf(nor,vec))>0.999999) { + if(fabs(Inpf(nor,xvec))>0.999999) { + nor[0] = 0.0f; + nor[1] = 1.0f; + nor[2] = 0.0f; + } + else { + nor[0] = 1.0f; + nor[1] = 0.0f; + nor[2] = 0.0f; + } + } + Crossf(side, nor, vec); + Normalize(side); + Crossf(nor, vec, side); + + Mat4One(mat); + VECCOPY(mat[0], vec); + VECCOPY(mat[1], side); + VECCOPY(mat[2], nor); + } + + *scale= len; } |