/** * $Id:$ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * The contents of this file may be used under the terms of either the GNU * General Public License Version 2 or later (the "GPL", see * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or * later (the "BL", see http://www.blender.org/BL/ ) which has to be * bought from the Blender Foundation to become active, in which case the * above mentioned GPL option does not apply. * * The Original Code is Copyright (C) 2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ /* effect.c MIX MODEL * * dec 95 * */ #include "blender.h" #include "effect.h" Effect *add_effect(int type) { Effect *eff=0; BuildEff *bld; PartEff *paf; WaveEff *wav; int a; switch(type) { case EFF_BUILD: bld= callocN(sizeof(BuildEff), "neweff"); eff= (Effect *)bld; bld->sfra= 1.0; bld->len= 100.0; break; case EFF_PARTICLE: paf= callocN(sizeof(PartEff), "neweff"); eff= (Effect *)paf; paf->sta= 1.0; paf->end= 100.0; paf->lifetime= 50.0; for(a=0; alife[a]= 50.0; paf->child[a]= 4; paf->mat[a]= 1; } paf->totpart= 1000; paf->totkey= 8; paf->defvec[2]= 1.0; paf->nabla= 0.05; break; case EFF_WAVE: wav= callocN(sizeof(WaveEff), "neweff"); eff= (Effect *)wav; wav->flag |= (WAV_X+WAV_Y+WAV_CYCL); wav->height= 0.5; wav->width= 1.5; wav->speed= 0.5; wav->narrow= 1.5; wav->lifetime= 0.0; wav->damp= 10.0; break; } eff->type= eff->buttype= type; eff->flag |= SELECT; return eff; } void free_effect(Effect *eff) { PartEff *paf; if(eff->type==EFF_PARTICLE) { paf= (PartEff *)eff; if(paf->keys) freeN(paf->keys); } freeN(eff); } void free_effects(ListBase *lb) { Effect *eff; while(eff= lb->first) { remlink(lb, eff); free_effect(eff); } } Effect *copy_effect(Effect *eff) { Effect *effn; effn= dupallocN(eff); if(effn->type==EFF_PARTICLE) ((PartEff *)effn)->keys= 0; return effn; } void copy_act_effect(Object *ob) { /* return de aktieve eff gekopieerd */ Effect *effn, *eff; eff= ob->effect.first; while(eff) { if(eff->flag & SELECT) { effn= copy_effect(eff); addtail(&ob->effect, effn); eff->flag &= ~SELECT; return; } eff= eff->next; } /* als tie hier komt: new effect */ eff= add_effect(EFF_BUILD); addtail(&ob->effect, eff); } void copy_effects(ListBase *lbn, ListBase *lb) { Effect *eff, *effn; BuildEff *bld; PartEff *paf; free_effects(lbn); eff= lb->first; while(eff) { effn= copy_effect(eff); addtail(lbn, effn); eff= eff->next; } } void deselectall_eff(Object *ob) { Effect *eff= ob->effect.first; while(eff) { eff->flag &= ~SELECT; eff= eff->next; } } void set_buildvars(Object *ob, int *start, int *end) { Mesh *me; Curve *cu; BuildEff *bld; float ctime; bld= ob->effect.first; while(bld) { if(bld->type==EFF_BUILD) { ctime= system_time(ob, 0, (float)CFRA, bld->sfra-1.0); if(ctime < 0.0) { *end= *start; } else if(ctime < bld->len) { *end= *start+(*end - *start)*ctime/bld->len; } return; } bld= bld->next; } } /* ***************** PARTICLES ***************** */ Particle *new_particle(PartEff *paf) { static Particle *pa; static int cur; /* afspraak: als paf->keys==0: alloc */ if(paf->keys==0) { pa= paf->keys= callocN( paf->totkey*paf->totpart*sizeof(Particle), "particlekeys" ); cur= 0; } else { if(cur && curtotpart) pa+=paf->totkey; cur++; } return pa; } PartEff *give_parteff(Object *ob) { PartEff *paf; paf= ob->effect.first; while(paf) { if(paf->type==EFF_PARTICLE) return paf; paf= paf->next; } return 0; } void where_is_particle(PartEff *paf, Particle *pa, float ctime, float *vec) { Particle *p[4]; float dt, t[4]; int a; if(paf->totkey==1) { VECCOPY(vec, pa->co); return; } /* eerst op zoek naar de eerste particlekey */ a= (paf->totkey-1)*(ctime-pa->time)/pa->lifetime; if(a>=paf->totkey) a= paf->totkey-1; pa+= a; if(a>0) p[0]= pa-1; else p[0]= pa; p[1]= pa; if(a+1totkey) p[2]= pa+1; else p[2]= pa; if(a+2totkey) p[3]= pa+2; else p[3]= p[2]; if(p[1]==p[2]) dt= 0.0; else dt= (ctime-p[1]->time)/(p[2]->time - p[1]->time); if(paf->flag & PAF_BSPLINE) set_four_ipo(dt, t, KEY_BSPLINE); else set_four_ipo(dt, t, KEY_CARDINAL); vec[0]= t[0]*p[0]->co[0] + t[1]*p[1]->co[0] + t[2]*p[2]->co[0] + t[3]*p[3]->co[0]; vec[1]= t[0]*p[0]->co[1] + t[1]*p[1]->co[1] + t[2]*p[2]->co[1] + t[3]*p[3]->co[1]; vec[2]= t[0]*p[0]->co[2] + t[1]*p[1]->co[2] + t[2]*p[2]->co[2] + t[3]*p[3]->co[2]; } void particle_tex(MTex *mtex, PartEff *paf, float *co, float *no) { extern float Tin, Tr, Tg, Tb; float old; externtex(mtex, co); if(paf->texmap==PAF_TEXINT) { Tin*= paf->texfac; no[0]+= Tin*paf->defvec[0]; no[1]+= Tin*paf->defvec[1]; no[2]+= Tin*paf->defvec[2]; } else if(paf->texmap==PAF_TEXRGB) { no[0]+= (Tr-0.5)*paf->texfac; no[1]+= (Tg-0.5)*paf->texfac; no[2]+= (Tb-0.5)*paf->texfac; } else { /* PAF_TEXGRAD */ old= Tin; co[0]+= paf->nabla; externtex(mtex, co); no[0]+= (old-Tin)*paf->texfac; co[0]-= paf->nabla; co[1]+= paf->nabla; externtex(mtex, co); no[1]+= (old-Tin)*paf->texfac; co[1]-= paf->nabla; co[2]+= paf->nabla; externtex(mtex, co); no[2]+= (old-Tin)*paf->texfac; } } void make_particle_keys(int depth, int nr, PartEff *paf, Particle *part, float *force, int deform, MTex *mtex) { Particle *pa, *opa; float damp, deltalife; int b, rt1, rt2; damp= 1.0-paf->damp; pa= part; /* startsnelheid: random */ if(paf->randfac!=0.0) { pa->no[0]+= paf->randfac*(rand()/32767.0 -0.5); pa->no[1]+= paf->randfac*(rand()/32767.0 -0.5); pa->no[2]+= paf->randfac*(rand()/32767.0 -0.5); } /* startsnelheid: texture */ if(mtex && paf->texfac!=0.0) { particle_tex(mtex, paf, pa->co, pa->no); } /* keys */ if(paf->totkey>1) { deltalife= pa->lifetime/(paf->totkey-1); opa= pa; pa++; b= paf->totkey-1; while(b--) { /* nieuwe tijd */ pa->time= opa->time+deltalife; /* nieuwe plek */ pa->co[0]= opa->co[0] + deltalife*opa->no[0]; pa->co[1]= opa->co[1] + deltalife*opa->no[1]; pa->co[2]= opa->co[2] + deltalife*opa->no[2]; /* nieuwe snelheid */ pa->no[0]= opa->no[0] + deltalife*force[0]; pa->no[1]= opa->no[1] + deltalife*force[1]; pa->no[2]= opa->no[2] + deltalife*force[2]; /* snelheid: texture */ if(mtex && paf->texfac!=0.0) { particle_tex(mtex, paf, pa->co, pa->no); } if(damp!=1.0) { pa->no[0]*= damp; pa->no[1]*= damp; pa->no[2]*= damp; } opa= pa; pa++; /* opa wordt onderin ook gebruikt */ } } if(deform) { /* alle keys deformen */ pa= part; b= paf->totkey; while(b--) { calc_latt_deform(pa->co); pa++; } } /* de grote vermenigvuldiging */ if(depthmult[depth]!=0.0) { /* uit gemiddeld 'mult' deel van de particles ontstaan 'child' nieuwe */ damp = nr; rt1= damp*paf->mult[depth]; rt2= (damp+1.0)*paf->mult[depth]; if(rt1!=rt2) { for(b=0; bchild[depth]; b++) { pa= new_particle(paf); *pa= *opa; pa->lifetime= paf->life[depth]; if(paf->randlife!=0.0) { pa->lifetime*= 1.0+ paf->randlife*(rand()/32767.0 - 0.5); } pa->mat_nr= paf->mat[depth]; make_particle_keys(depth+1, b, paf, pa, force, deform, mtex); } } } } void build_particle_system(Object *ob) { Object *par; PartEff *paf; Particle *pa; Mesh *me; MVert *mvert; MTex *mtexcol=0, *mtexmove=0; Material *ma; float framelenont, ftime, dtime, force[3], imat[3][3], deltalife, vec[3]; float ofs, fac, prevobmat[4][4], child, sfraont; int deform=0, turbul=1, a, cur, cfraont, cfralast, totpart, delta; short *sp; if(ob->type!=OB_MESH) return; me= ob->data; if(me->totvert==0) return; ma= give_current_material(ob, 1); if(ma) { mtexmove= ma->mtex[7]; mtexcol= ma->mtex[0]; } paf= give_parteff(ob); if(paf==0) return; waitcursor(1); /* alle particles genereren */ if(paf->keys) freeN(paf->keys); paf->keys= 0; new_particle(paf); cfraont= CFRA; cfralast= -1000; framelenont= G.scene->r.framelen; G.scene->r.framelen= 1.0; /* sfraont= ob->sf; */ /* ob->sf= 0.0; */ /* mult generaties? */ totpart= paf->totpart; for(a=0; amult[a]!=0.0) { /* interessante formule! opdezewijze is na 'x' generaties het totale aantal paf->totpart */ totpart/= (1.0+paf->mult[a]*paf->child[a]); } else break; } ftime= paf->sta; dtime= (paf->end - paf->sta)/totpart; /* hele hiera onthouden */ par= ob; while(par) { pushdata(par, sizeof(Object)); par= par->parent; } /* alles op eerste frame zetten */ CFRA= cfralast= ffloor(ftime); par= ob; while(par) { /* do_ob_ipo(par); */ do_ob_key(par); par= par->parent; } do_mat_ipo(ma); where_is_object(ob); Mat4CpyMat4(prevobmat, ob->obmat); Mat4Invert(ob->imat, ob->obmat); Mat3CpyMat4(imat, ob->imat); srand(paf->seed); /* gaat anders veuls te hard */ force[0]= paf->force[0]*0.05; force[1]= paf->force[1]*0.05; force[2]= paf->force[2]*0.05; deform= (ob->parent && ob->parent->type==OB_LATTICE); if(deform) init_latt_deform(ob->parent, 0); for(a=0; atime= ftime; /* ob op juiste tijd zetten */ cur= ffloor(ftime) + 1 ; /* + 1 heeft een reden: (obmat/prevobmat) anders beginnen b.v. komeetstaartjes te laat */ if(cfralast != cur) { CFRA= cfralast= cur; /* later bijgevoegd: blur? */ system_time(ob, ob->parent, (float)CFRA, 0.0); par= ob; while(par) { /* do_ob_ipo(par); */ par->ctime= -1234567.0; do_ob_key(par); par= par->parent; } do_mat_ipo(ma); Mat4CpyMat4(prevobmat, ob->obmat); where_is_object(ob); Mat4Invert(ob->imat, ob->obmat); Mat3CpyMat4(imat, ob->imat); } /* coordinaat ophalen */ mvert= me->mvert + (a % me->totvert); VECCOPY(pa->co, mvert->co); Mat4MulVecfl(ob->obmat, pa->co); VECCOPY(vec, mvert->co); Mat4MulVecfl(prevobmat, vec); /* eerst even startsnelheid: object */ VecSubf(pa->no, pa->co, vec); VecMulf(pa->no, paf->obfac); /* nu juiste interframe co berekenen */ fac= (ftime- ffloor(ftime)); pa->co[0]= fac*pa->co[0] + (1.0-fac)*vec[0]; pa->co[1]= fac*pa->co[1] + (1.0-fac)*vec[1]; pa->co[2]= fac*pa->co[2] + (1.0-fac)*vec[2]; /* startsnelheid: normaal */ if(paf->normfac!=0.0) { sp= mvert->no; /* transpose ! */ vec[0]= imat[0][0]*sp[0]+imat[0][1]*sp[1]+imat[0][2]*sp[2]; vec[1]= imat[1][0]*sp[0]+imat[1][1]*sp[1]+imat[1][2]*sp[2]; vec[2]= imat[2][0]*sp[0]+imat[2][1]*sp[1]+imat[2][2]*sp[2]; Normalise(vec); VecMulf(vec, paf->normfac); VecAddf(pa->no, pa->no, vec); } pa->lifetime= paf->lifetime; if(paf->randlife!=0.0) { pa->lifetime*= 1.0+ paf->randlife*(rand()/32767.0 - 0.5); } pa->mat_nr= 1; make_particle_keys(0, a, paf, pa, force, deform, mtexmove); } if(deform) end_latt_deform(); /* restore */ CFRA= cfraont; G.scene->r.framelen= framelenont; /* hele hiera terug */ par= ob; while(par) { popfirst(par, sizeof(Object)); /* geen ob->ipo doen: insertkey behouden */ do_ob_key(par); par= par->parent; } /* restore: NA popfirst */ /* ob->sf= sfraont; */ waitcursor(0); } /* ************* WAVE **************** */ void calc_wave_deform(WaveEff *wav, float ctime, float *co) { /* co is in lokale coords */ float lifefac, x, y, amplit; /* mag eigenlijk niet voorkomen */ if((wav->flag & (WAV_X+WAV_Y))==0) return; lifefac= wav->height; if( wav->lifetime!=0.0) { x= ctime - wav->timeoffs; if(x>wav->lifetime) { lifefac= x-wav->lifetime; if(lifefac > wav->damp) lifefac= 0.0; else lifefac= wav->height*(1.0 - fsqrt(lifefac/wav->damp)); } } if(lifefac==0.0) return; x= co[0]-wav->startx; y= co[1]-wav->starty; if(wav->flag & WAV_X) { if(wav->flag & WAV_Y) amplit= fsqrt( (x*x + y*y)); else amplit= x; } else amplit= y; /* zo maaktie mooie cirkels */ amplit-= (ctime-wav->timeoffs)*wav->speed; if(wav->flag & WAV_CYCL) { amplit = fmodf(amplit-wav->width, 2.0*wav->width) + wav->width; } /* GAUSSIAN */ if(amplit> -wav->width && amplitwidth) { amplit = amplit*wav->narrow; amplit= 1.0/exp(amplit*amplit) - wav->minfac; co[2]+= lifefac*amplit; } } void object_wave(Object *ob) { WaveEff *wav; DispList *dl; Mesh *me; MVert *mvert; float *fp, ctime; int a, first; /* is er een mave */ wav= ob->effect.first; while(wav) { if(wav->type==EFF_WAVE) break; wav= wav->next; } if(wav==0) return; if(ob->type==OB_MESH) { ctime= system_time(ob, 0, (float)CFRA, 0.0); first= 1; me= ob->data; dl= find_displist_create(&ob->disp, DL_VERTS); if(dl->verts) freeN(dl->verts); dl->nr= me->totvert; dl->verts= mallocN(3*4*me->totvert, "wave"); wav= ob->effect.first; while(wav) { if(wav->type==EFF_WAVE) { /* voorberekenen */ wav->minfac= 1.0/exp(wav->width*wav->narrow*wav->width*wav->narrow); if(wav->damp==0) wav->damp= 10.0; mvert= me->mvert; fp= dl->verts; for(a=0; atotvert; a++, mvert++, fp+=3) { if(first) VECCOPY(fp, mvert->co); calc_wave_deform(wav, ctime, fp); } first= 0; } wav= wav->next; } } }