particles.c

Go to the documentation of this file.
00001 // File particles.c
00002 
00003 #define MODULE_PARTICLES
00004 
00005 #include "render.h"
00006 #include "..\shaders\shaders.h"
00007 #include "..\gl2.h"
00008 
00009 extern int RENDERBUFFER_WIDTH;
00010 extern int RENDERBUFFER_HEIGHT;
00011 extern int TEXTUREBUFFER_WIDTH;
00012 extern int TEXTUREBUFFER_HEIGHT;
00013 extern GLuint g_check_texture;
00014 extern GLuint g_map_texture;
00015 extern GLuint g_ref_texture;  
00016 extern GLuint g_bump_texture;
00017 extern GLuint g_tran_texture;
00018 extern GLuint g_movie_texture;
00019 extern GLuint g_env_texture;
00020 extern GLuint g_envB_texture;
00021 extern GLuint g_envN_texture;
00022 extern GLuint g_noise_texture;
00023 extern GLuint g_env3D_texture;
00024 extern GLuint g_sky_texture;
00025 
00026 extern double DepthScalingGL,FrontDepthGL,BackDepthGL;
00027 
00028 extern char gszHomeDir[];
00029 extern double GlobalScale;
00030 
00031 #include "particles.h"
00032 
00033 // useful macro to guarantee that values are within a given range
00034 #define Clamp(x, min, max)  x = (x<min  ? min : x<max ? x : max);
00035 //A number between 0.0000 and 1.00000
00036 #define RAND_N ((float)(rand())/(float)(RAND_MAX))
00037 
00038 #define FRAME_TIME 0.04       // 25ms
00039 //#define PARTICLE_SCALE 32768.0
00040 //#define SIZE_SCALE 100.0
00041 //#define PARTICLE_SCALE 16384.0
00042 //#define SIZE_SCALE 400.0
00043 #define PARTICLE_SCALE 4096.0
00044 #define SIZE_SCALE 2500.0
00045 static long nParticleImages=NP_IMAGES;
00046 static long ParticleImageSize[NP_IMAGES];
00047 static unsigned char *ParticleImages[NP_IMAGES];
00048 static GLuint g_particle_textures[NP_IMAGES];
00049 static BOOL bParticleImageLoaded=FALSE;
00050 
00051 static BOOL InitParticleSystem(ParticleSystem *pPS);
00052 static void UpdateParticleSystem(ParticleSystem *pPS, double fTime);
00053 static BOOL UpdateParticle(Particle *p,  double fTimeDelta );
00054 static void InterpolateParticleSystemPosition(ParticleSystem *Ps, double ratio);
00055 static void FreeThisParticle(Particle *p, ParticleSystem *Pp);
00056 static void BlendFrameBufferParticle(double, double, double, double, double, long, long,
00057             Particle *, fullscreenbuffer *, float *);
00058 
00059 void LoadParticleImages(void){
00060  int i;
00061  long x,y;
00062  char pfile[256];
00063  for(i=0;i<nParticleImages;i++){
00064    ParticleImages[i]=NULL;
00065    strcpy(pfile,gszHomeDir); strcat(pfile,"PBM_"); strcat(pfile,ParticleList[i]),strcat(pfile,".bmp");
00066 //   ParticleImages[i]=LoadSystemMAP(FALSE,FALSE,pfile,&x,&y); // x must equal y (square images) // Don't scale
00067    ParticleImages[i]=LoadSystemMAP(FALSE,ParticleBits[i],pfile,&x,&y); // x must equal y (square images) // Don't scale
00068    ParticleImageSize[i]=x;
00069    //if(debug != NULL)fprintf(debug,"Load particle image %ld [%s] size %ld\n",i,pfile,x);
00070  }
00071  bParticleImageLoaded=TRUE;
00072 }
00073 
00074 void UnloadParticleImages(void){
00075   int i; for(i=0;i<nParticleImages;i++){
00076     if(ParticleImages[i] != NULL){
00077       //if(debug!= NULL)fprintf(debug,"unloading particle image %ld\n",i);
00078       X__Free(ParticleImages[i]);
00079       ParticleImages[i]=NULL;
00080     }
00081   }
00082   bParticleImageLoaded=FALSE;
00083 }
00084 
00085 void MakeParticleTextures(void){ // Make OpenGL textures from particle images
00086  int i,j,k;
00087  unsigned char *tex,*pi,*po;
00088  long gg;
00089  glGenTextures( nParticleImages, &g_particle_textures[0]);
00090  for(i=0;i<nParticleImages;i++){
00091    glBindTexture(GL_TEXTURE_2D,g_particle_textures[i]);
00092    if(ParticleBits[i]){
00093      glTexImage2D(GL_TEXTURE_2D,0,4,ParticleImageSize[i],ParticleImageSize[i],
00094                             0,GL_RGBA,GL_UNSIGNED_BYTE,
00095                             (GLvoid *)ParticleImages[i]);
00096    }
00097    else{
00098      if((tex=malloc(ParticleImageSize[i]*ParticleImageSize[i]*4*sizeof(unsigned char))) != NULL){
00099        pi=ParticleImages[i]; po=tex;
00100        for(j=0;j<ParticleImageSize[i];j++){
00101          for(k=0;k<ParticleImageSize[i];k++){
00102            *po++ = *pi++;  // R
00103            *po++ = gg= *pi++;  // G
00104            *po++ = *pi++;  // B
00105            *po++ = (unsigned char)(min(255,gg*2)); // alpha
00106          }
00107        }
00108        //if(debug != NULL)fprintf(debug,"making Particle Texture size %ld\n",ParticleImageSize[i]);
00109        if(tex != NULL)glTexImage2D(GL_TEXTURE_2D,0,4,ParticleImageSize[i],ParticleImageSize[i],
00110                                    0,GL_RGBA,GL_UNSIGNED_BYTE,
00111                                   (GLvoid *)tex);
00112        free(tex);   
00113     }
00114    }
00115    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00116    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00117  }
00118  glBindTexture(GL_TEXTURE_2D,0);
00119 }
00120 
00121 void ReleaseParticleTextures(void){
00122  //if(debug != NULL)fprintf(debug,"Releasing Particle Textures \n");
00123  glDeleteTextures(nParticleImages,g_particle_textures);
00124 }
00125 
00126 void  SetUpSingleParticle(ParticleSystem *ps){
00127  double mr,particle_transformation[4][4],trinv[4][4];
00128  vector Zero_Vector,dc;
00129  int i;
00130  Particle *p;
00131  ps->Rate=0;// should only make 1 particle
00132  InitParticleSystem(ps);
00133  if(ps->particles == NULL)return;
00134  ps->NumP=1;
00135  MakeObjectTransformation(ps->dPhi,ps->dTheta,ps->dAlpha,
00136               ps->im, ps->ima,
00137               ps->sx,ps->sy,ps->sz,
00138               Zero_Vector,ps->pin,
00139               particle_transformation,ps->particle_object_transformation,trinv);
00140  p=&ps->particles[0];
00141  p->fAge=1.0; // t0 allow for viewing
00142  mr=ps->mratio;
00143  if(mr > 0.5)mr  = (1.0-mr)*2.0;
00144  else        mr *=  2.0;
00145 
00146  p->fAlpha = ps->fAlphaStart+(ps->fAlphaEnd - ps->fAlphaStart)*mr; 
00147  VECSUB(ps->vColorEnd,ps->vColorStart,dc)
00148  VECCOPY(ps->vColorStart,p->c)
00149  VECSUM(p->c,mr*dc,p->c)
00150  p->fSize  = ps->fSizeStart+(ps->fSizeEnd - ps->fSizeStart)*mr;
00151  
00152  R_m4by4(ViewTransform,ps->particle_object_transformation,particle_transformation); 
00153  R_m4by1(particle_transformation,
00154         p->p[0]*PARTICLE_SCALE,p->p[1]*PARTICLE_SCALE,p->p[2]*PARTICLE_SCALE,
00155         &p->pfx[0],&p->pfx[1],&p->pfx[2]);
00156 }
00157 
00158 void  SetUpParticles(ParticleSystem *ps){
00159  double frame_time,time,delta_time=0.01,time_burst,time_burst_interval,time_burst_pulse;
00160  double particle_transformation[4][4],trinv[4][4];
00161  vector Zero_Vector;
00162  int i,steps,np;
00163  Particle *p;
00164  //if(debug != NULL)fprintf(debug,"Particle system setup Np=%ld\n",ps->Rate);
00165  // First build the particle system and move it into "local" position 
00166  InitParticleSystem(ps);
00167  // dframe is the absolute time, in number of frames along timeline 
00168  frame_time=ps->dframe*FRAME_TIME;
00169  if(ps->bSteadyState)frame_time += ps->fLifeTime;
00170   // NB:  we MUST get the same sequence of random numbers every time
00171  steps=(int)(frame_time/delta_time);  // number of steps to run particle model for
00172  steps=max(steps,1);
00173  //if(debug != NULL)fprintf(debug,"burst=%ld dframe=%ld steps=%ld frame_time=%lf\n",ps->bBurst,ps->dframe,steps,frame_time);
00174  srand((unsigned int)ps->NumP);
00175  if(ps->bBurst){
00176    time_burst=0.0;  
00177    time_burst_interval = 1.100*ps->fLifeTime; // how often pulse repeats
00178    time_burst_pulse    = 0.075*ps->fLifeTime;
00179  }
00180  ps->bSuppress=FALSE;
00181  time=0.0;
00182  if(!ps->bSpinOff)MakeObjectTransformation(ps->dPhi,ps->dTheta,ps->dAlpha, // keep the particle system relative to local frame of reference
00183               ps->im, ps->ima,
00184               ps->sx,ps->sy,ps->sz,
00185               Zero_Vector,ps->pin,
00186               particle_transformation,ps->particle_object_transformation,trinv);
00187  // bring the particle system up to date by stepping from the start
00188  for(i=0;i<steps;i++){
00189    if(ps->bSpinOff){
00190      InterpolateParticleSystemPosition(ps,((double)i/(double)steps));
00191      MakeObjectTransformation(ps->tdPhi,ps->tdTheta,ps->tdAlpha,
00192               ps->tim, ps->tima,
00193               ps->tsx,ps->tsy,ps->tsz,
00194               Zero_Vector,ps->tpin,
00195               particle_transformation,ps->particle_object_transformation,trinv);
00196 
00197    }
00198    if(ps->bBurst){  // if bursting and in quiet period - suppress particle emission
00199      if(time_burst < time_burst_interval){
00200        if(time_burst < time_burst_pulse)ps->bSuppress=FALSE;
00201        else                             ps->bSuppress=TRUE;
00202        time_burst += delta_time;
00203      }
00204      else time_burst = 0.0;
00205    }
00206    UpdateParticleSystem(ps,time);
00207    time += delta_time;
00208    //if(debug != NULL)fprintf(debug,"time=%lf time_burst=%lf\n",time,time_burst);
00209  }
00210  np=ps->NumP;  // number of particles 
00211  if(!ps->bSpinOff){ // particles remain in the local frame of reference 
00212    R_m4by4(ViewTransform,ps->particle_object_transformation,particle_transformation);  // include the viewing transform
00213    for(i=0;i<np;i++){
00214      p=&ps->particles[i];
00215      if(p->fAge < 0.0)continue;
00216      R_m4by1(particle_transformation,
00217            p->p[0]*PARTICLE_SCALE,p->p[1]*PARTICLE_SCALE,p->p[2]*PARTICLE_SCALE,
00218            &p->pfx[0],&p->pfx[1],&p->pfx[2]);
00219    } 
00220  }
00221  else{
00222    for(i=0;i<np;i++){
00223      p=&ps->particles[i];
00224      if(p->fAge < 0.0)continue;
00225      R_m4by1(ViewTransform,p->p[0],p->p[1],p->p[2],&p->pfx[0],&p->pfx[1],&p->pfx[2]);
00226    } 
00227  }
00228 }
00229 
00230 static BOOL InitParticleSystem(ParticleSystem *pPS){
00231 int i;
00232 double s;
00233 // assign these values from the settings in the animator
00234 pPS->bSuppress=FALSE;
00235 pPS->fTimeLastUpdate  = 0.0;
00236 pPS->fEmissionResidue = 0.0;
00237 pPS->vLocation[0]     = pPS->vLocation[1]     = pPS->vLocation[2]     = 0.0; 
00238 pPS->vPrevLocation[0] = pPS->vPrevLocation[1] = pPS->vPrevLocation[2] = 0.0; 
00239 pPS->vTempVelocity[0] = pPS->vTempVelocity[1] = pPS->vTempVelocity[2] = 0.0; 
00240 
00241 pPS->vColorStart[0]   = (double)(pPS->colour_start[0])/255.0; 
00242 pPS->vColorStart[1]   = (double)(pPS->colour_start[1])/255.0; 
00243 pPS->vColorStart[2]   = (double)(pPS->colour_start[2])/255.0; 
00244 pPS->vColorEnd[0]     = (double)(pPS->colour_end[0])/255.0; 
00245 pPS->vColorEnd[1]     = (double)(pPS->colour_end[1])/255.0; 
00246 pPS->vColorEnd[2]     = (double)(pPS->colour_end[2])/255.0; 
00247 pPS->vColorVar[0]     = (double)(pPS->vcolour)*0.001;
00248 pPS->vColorVar[1]     = (double)(pPS->vcolour)*0.001;
00249 pPS->vColorVar[2]     = (double)(pPS->vcolour)*0.001;
00250 pPS->fAlphaStart      = (double)(pPS->alpha_start)*0.001;
00251 pPS->fAlphaVar        = (double)(pPS->valpha)*0.001;
00252 pPS->fAlphaEnd        = (double)(pPS->alpha_end)*0.001;
00253 pPS->fSizeStart       = (double)(pPS->size_start)*0.001*MAX_SIZE;  pPS->fSizeStart=max(0.1,pPS->fSizeStart);
00254 pPS->fSizeVar         = (double)(pPS->vsize)*0.001*MAX_SIZE;
00255 pPS->fSizeEnd         = (double)(pPS->size_end)*0.001*MAX_SIZE;    pPS->fSizeEnd=max(0.1,pPS->fSizeEnd);
00256 pPS->fSpeed           = (double)(pPS->speed)*0.001*MAX_SPEED;
00257 pPS->fSpeedVar        = (double)(pPS->vspeed)*0.001*MAX_SPEED/10.0;
00258 pPS->fTheta           = (double)(pPS->theta)*0.001;
00259 pPS->fLifeTime        = (double)(pPS->life)*0.001*MAX_LIFETIME;    pPS->fLifeTime=max(0.1,pPS->fLifeTime);
00260 pPS->fLifeVar         = (double)(pPS->vlife)*0.001*MAX_LIFETIME;
00261 pPS->vGravityStart[0] = (double)(pPS->ew_start)*0.001*(MAX_GRAVITY-MIN_GRAVITY);
00262 pPS->vGravityStart[1] = (double)(pPS->ns_start)*0.001*(MAX_GRAVITY-MIN_GRAVITY);
00263 pPS->vGravityStart[2] = (double)(pPS->ud_start)*0.001*(MAX_GRAVITY-MIN_GRAVITY);
00264 pPS->vGravityEnd[0]   = (double)(pPS->ew_end)*0.001*(MAX_GRAVITY-MIN_GRAVITY);
00265 pPS->vGravityEnd[1]   = (double)(pPS->ns_end)*0.001*(MAX_GRAVITY-MIN_GRAVITY);
00266 pPS->vGravityEnd[2]   = (double)(pPS->ud_end)*0.001*(MAX_GRAVITY-MIN_GRAVITY);
00267 s=(double)(pPS->particle_size_scale)*0.001;  // 0 - 1
00268 if(s < 0.5){
00269  s=1.0+(0.5-s)*2.0*9.0;  // 10 - 1
00270  s=1.0/s;
00271 }
00272 else {
00273   s=1.0+((s-0.5)*2.0*9.0);  // magnification by  1 up to 10
00274 }
00275 pPS->fSizeScale       = s;
00276 pPS->fGravityVar      = 0.00f; 
00277 pPS->uParticlesPerSec = pPS->Rate;  // related to NumP  - should be the default
00278 pPS->NumP=(long)((double)pPS->Rate*pPS->fLifeTime*10.0);  // should be long enough for all particles to be alive > no/sec * lifetime
00279 pPS->NumP=max(pPS->NumP,1);
00280 #if 0
00281 if(debug != NULL){
00282   fprintf(debug,"iid=%ld name=[%s] [%s]\n",pPS->iid,ParticleList[pPS->iid],pPS->ImageName);
00283   fprintf(debug,"%lf\n",pPS->vColorStart[0]);
00284   fprintf(debug,"%lf\n",pPS->vColorStart[1]);
00285   fprintf(debug,"%lf\n",pPS->vColorStart[2]);
00286   fprintf(debug,"%lf\n",pPS->vColorEnd[0]);
00287   fprintf(debug,"%lf\n",pPS->vColorEnd[1]);
00288   fprintf(debug,"%lf\n",pPS->vColorEnd[2]);
00289   fprintf(debug,"Color Var %lf\n",pPS->vColorVar[0]);
00290   fprintf(debug,"Rate %ld\n",pPS->uParticlesPerSec);
00291   fprintf(debug,"NumP %ld\n",pPS->NumP);
00292   fprintf(debug,"AS %lf\n",pPS->fAlphaStart);
00293   fprintf(debug,"AV %lf\n",pPS->fAlphaVar);
00294   fprintf(debug,"AE %lf\n",pPS->fAlphaEnd);
00295   fprintf(debug,"size %lf\n",pPS->fSizeStart);
00296   fprintf(debug,"size var %lf\n",pPS->fSizeVar);
00297   fprintf(debug,"size end %lf\n",pPS->fSizeEnd);
00298   fprintf(debug,"speed %lf\n",pPS->fSpeed);
00299   fprintf(debug,"speed var %lf\n",pPS->fSpeedVar);
00300   fprintf(debug,"theta %lf\n",pPS->fTheta);
00301   fprintf(debug,"lifetime %lf\n",pPS->fLifeTime);
00302   fprintf(debug,"life var%lf\n",pPS->fLifeVar);
00303   fprintf(debug,"particle size scale %lf\n",pPS->fSizeScale);
00304   fprintf(debug,"Gravity\n");
00305   fprintf(debug,"s %lf\n",pPS->vGravityStart[0]);
00306   fprintf(debug,"s %lf\n",pPS->vGravityStart[1]);
00307   fprintf(debug,"s %lf\n",pPS->vGravityStart[2]);
00308   fprintf(debug,"e %lf\n",pPS->vGravityEnd[0]);
00309   fprintf(debug,"e %lf\n",pPS->vGravityEnd[1]);
00310   fprintf(debug,"e %lf\n",pPS->vGravityEnd[2]);
00311 }
00312 #endif
00313 if(pPS->NumP > 0){
00314   pPS->particles=(Particle *)X__Malloc(pPS->NumP*sizeof(Particle));
00315   for(i=0;i<pPS->NumP;i++){
00316     pPS->particles[i].fAge = -1.0;  // particle is not part of the system initially
00317   }
00318 }
00319 else pPS->particles=NULL;
00320 return (TRUE);
00321 }
00322 
00323 // update the particle system to the new time (using old time as starting point)
00324 // this is called as part of the startup process to bring the particle system up to
00325 // date for the frame being rendered.
00326 static void UpdateParticleSystem(ParticleSystem *pPS, double fTime){
00327  int i;
00328  vector vLocation;
00329  double fTimeDelta;
00330  double fParticlesNeeded;
00331  double RandomYaw;
00332  double RandomPitch;
00333  double fNewSpeed;
00334  unsigned int uParticlesCreated,uParticlesAlive;
00335  Particle *pP;
00336  fTimeDelta = fTime - pPS->fTimeLastUpdate;
00337  pPS->fTimeLastUpdate = fTime;
00338  vLocation[0] = 0.0f;
00339  vLocation[1] = 0.0f;
00340  vLocation[2] = 0.0f;
00341  uParticlesAlive = 0;
00342  pP = pPS->particles;
00343  if(pP == NULL)return;
00344  for(i=0;i<pPS->NumP;i++){  // update the particles
00345    if (pP[i].fAge >= 0.0f ){
00346      if(UpdateParticle(&(pP[i]),fTimeDelta ))uParticlesAlive++;
00347    }
00348  }
00349  fParticlesNeeded = pPS->uParticlesPerSec * fTimeDelta + pPS->fEmissionResidue;
00350  if(pPS->bSuppress){
00351    uParticlesCreated = 0;
00352    pPS->fEmissionResidue = 0.0;
00353  }
00354  else{
00355    uParticlesCreated = (unsigned int)fParticlesNeeded;
00356    pPS->fEmissionResidue = fParticlesNeeded - uParticlesCreated;
00357  }
00358  //if(debug != NULL)fprintf(debug,"Update particle system time=%lf dt=%lf Up created=%ld alive=%ld\n",fTime,fTimeDelta,uParticlesCreated,uParticlesAlive);
00359  if (uParticlesCreated > 0 ) {
00360    for (i=0; i<pPS->NumP; i++ ){
00361     if(!uParticlesCreated)break;
00362     if( pP[i].fAge < 0.0f ) {
00363        pP[i].fAge = 0.0f;
00364        pP[i].fLifetime = pPS->fLifeTime+RAND_N * pPS->fLifeVar;
00365        Clamp( pP[i].fLifetime, MIN_LIFETIME, MAX_LIFETIME ); 
00366        pP[i].fAlpha = pPS->fAlphaStart + RAND_N * pPS->fAlphaVar;
00367        Clamp( pP[i].fAlpha, MIN_ALPHA, MAX_ALPHA );
00368        pP[i].fAlphaDelta = (pPS->fAlphaEnd - pP[i].fAlpha) / pP[i].fLifetime;
00369        pP[i].c[0] = pPS->vColorStart[0] + RAND_N * pPS->vColorVar[0];
00370        pP[i].c[1] = pPS->vColorStart[1] + RAND_N * pPS->vColorVar[1];
00371        pP[i].c[2] = pPS->vColorStart[2] + RAND_N * pPS->vColorVar[2];
00372        Clamp( pP[i].c[0], 0.0f, 1.0f );
00373        Clamp( pP[i].c[1], 0.0f, 1.0f );
00374        Clamp( pP[i].c[2], 0.0f, 1.0f );
00375        pP[i].dc[0]=((pPS->vColorEnd[0]+RAND_N*pPS->vColorVar[0])-pP[i].c[0])/pP[i].fLifetime;
00376        pP[i].dc[1]=((pPS->vColorEnd[1]+RAND_N*pPS->vColorVar[1])-pP[i].c[1])/pP[i].fLifetime;
00377        pP[i].dc[2]=((pPS->vColorEnd[2]+RAND_N*pPS->vColorVar[2])-pP[i].c[2])/pP[i].fLifetime;
00378        pP[i].fSize= pPS->fSizeStart + RAND_N * pPS->fSizeVar;
00379        Clamp( pP[i].fSize, MIN_SIZE, MAX_SIZE );
00380        pP[i].fSizeDelta = (pPS->fSizeEnd - pP[i].fSize) / pP[i].fLifetime;
00381        pP[i].g[0]=pPS->vGravityStart[0]*GRAVITY+RAND_N*pPS->fGravityVar*GRAVITY;
00382        Clamp( pP[i].g[0], MIN_GRAVITY*GRAVITY, MAX_GRAVITY*GRAVITY );
00383        pP[i].g[1]=pPS->vGravityStart[1]*GRAVITY+RAND_N*pPS->fGravityVar*GRAVITY;
00384        Clamp( pP[i].g[1], MIN_GRAVITY*GRAVITY, MAX_GRAVITY*GRAVITY );
00385        pP[i].g[2]=pPS->vGravityStart[2]*GRAVITY+RAND_N*pPS->fGravityVar*GRAVITY;
00386        Clamp( pP[i].g[2], MIN_GRAVITY*GRAVITY, MAX_GRAVITY*GRAVITY );
00387        pP[i].dg[0] = ( pPS->vGravityEnd[0]*GRAVITY - pP[i].g[0] ) / pP[i].fLifetime;
00388        pP[i].dg[1] = ( pPS->vGravityEnd[1]*GRAVITY - pP[i].g[1] ) / pP[i].fLifetime;
00389        pP[i].dg[2] = ( pPS->vGravityEnd[2]*GRAVITY - pP[i].g[2] ) / pP[i].fLifetime;
00390        pPS->vTempVelocity[0] = (pPS->vLocation[0] - pPS->vPrevLocation[0])/fTimeDelta;
00391        pPS->vTempVelocity[1] = (pPS->vLocation[1] - pPS->vPrevLocation[1])/fTimeDelta;
00392        pPS->vTempVelocity[2] = (pPS->vLocation[2] - pPS->vPrevLocation[2])/fTimeDelta;
00393        pP[i].p[0] = pPS->vPrevLocation[0];
00394        pP[i].p[1] = pPS->vPrevLocation[1];
00395        pP[i].p[2] = pPS->vPrevLocation[2];
00396        pP[i].pl[0] = pP[i].p[0];
00397        pP[i].pl[1] = pP[i].p[1];
00398        pP[i].pl[2] = pP[i].p[2];
00399        RandomYaw = RAND_N * 3.14159f * 2.0f;
00400        RandomPitch = RAND_N * pPS->fTheta * 3.14159f;
00401        pP[i].v[2] = cos( RandomPitch );  // up - down 
00402        pP[i].v[0] = sin(RandomPitch) * cos(RandomYaw);
00403        pP[i].v[1] = sin(RandomPitch) * sin(RandomYaw);
00404        fNewSpeed = pPS->fSpeed + RAND_N * pPS->fSpeedVar;
00405        Clamp( fNewSpeed, MIN_SPEED, MAX_SPEED );
00406        pP[i].v[0] *= fNewSpeed ;
00407        pP[i].v[1] *= fNewSpeed ;
00408        pP[i].v[2] *= fNewSpeed ;
00409        if(pPS->bSpinOff)FreeThisParticle(&(pP[i]),pPS);
00410        else pP[i].bSpin=FALSE; 
00411        uParticlesCreated--;
00412      }
00413    }
00414  }
00415  VECCOPY(pPS->vLocation,pPS->vPrevLocation)
00416 }
00417 
00418 // update the position and other attribes of a particle within a particle system 
00419 static BOOL UpdateParticle(Particle *p,  double fTimeDelta ){
00420  if ( p->fAge + fTimeDelta >= p->fLifetime ) {
00421    p->fAge = -1.0f;
00422    return FALSE;
00423  }
00424  else{
00425    p->fAge += fTimeDelta;
00426    VECCOPY(p->p,p->pl)
00427    VECSUM(p->p,fTimeDelta*p->v,p->p)
00428    VECSUM(p->v,9.8*fTimeDelta*p->g,p->v)  
00429    p->fAlpha += p->fAlphaDelta * fTimeDelta;
00430    VECSUM(p->c,fTimeDelta*p->dc,p->c)
00431    p->fSize += p->fSizeDelta * fTimeDelta;
00432    VECSUM(p->g,fTimeDelta*p->dg,p->g)
00433    if(p->bSpin && R_Nground > 0){
00434      if(p->p[2] < Ground.pin[2]){
00435        p->p[2]=Ground.pin[2];  // don't allow to go below ground
00436        p->v[2] = -0.5*p->v[2]; // rebound
00437      }
00438    }
00439  }
00440  return TRUE;
00441 }
00442 
00443 
00444 static void FreeThisParticle(Particle *p, ParticleSystem *Pp){
00445  // the particle breaks free from the particle system local frame of reference and moves so that
00446  // it is now relative to the global reference frame.  Things like smoke from a steam train, or a moving
00447  // flame drift off.
00448  vector t;
00449  p->bSpin=TRUE;
00450  R_m4by1(Pp->particle_object_transformation,
00451          p->p[0]*PARTICLE_SCALE,p->p[1]*PARTICLE_SCALE,p->p[2]*PARTICLE_SCALE,
00452          &t[0],&t[1],&t[2]);
00453  VECCOPY(t,p->p);
00454  R_m3by1(Pp->particle_object_transformation, 
00455          p->v[0]*PARTICLE_SCALE,p->v[1]*PARTICLE_SCALE,p->v[2]*PARTICLE_SCALE,
00456          &t[0],&t[1],&t[2]);
00457  VECCOPY(t,p->v);
00458 #if 0
00459  // perhaps gravity should always be downward
00460  R_m3by1(Pp->particle_object_transformation, 
00461          p->g[0]*PARTICLE_SCALE,p->g[1]*PARTICLE_SCALE,p->g[2]*PARTICLE_SCALE,
00462          &t[0],&t[1],&t[2]);
00463  VECCOPY(t,p->g);
00464  R_m3by1(Pp->particle_object_transformation, 
00465          p->dg[0]*PARTICLE_SCALE,p->dg[1]*PARTICLE_SCALE,p->dg[2]*PARTICLE_SCALE,
00466          &t[0],&t[1],&t[2]);
00467  VECCOPY(t,p->dg);
00468 #else
00469  VECSCALE(PARTICLE_SCALE,p->g,p->g) 
00470  VECSCALE(PARTICLE_SCALE,p->dg,p->dg) 
00471 #endif
00472 
00473 }
00474 
00475 static void InterpolateParticleSystemPosition(ParticleSystem *Ps, double ratio){
00476  double dp;
00477  vector dv;
00478  dp = Ps->dPhi - Ps->sdPhi;
00479  if(dp < -180.0)dp += 360.0;
00480  if(dp >  180.0)dp -= 360.0;
00481  dp *= ratio;
00482  dp += Ps->sdPhi;
00483  if(dp < -180.0)dp += 360.0;
00484  if(dp >  180.0)dp -= 360.0;
00485  Ps->tdPhi = dp;
00486  dp = Ps->dAlpha - Ps->sdAlpha;
00487  if(dp < -180.0)dp += 360.0;
00488  if(dp >  180.0)dp -= 360.0;
00489  dp *= ratio;
00490  dp += Ps->sdAlpha;
00491  if(dp < -180.0)dp += 360.0;
00492  if(dp >  180.0)dp -= 360.0;
00493  Ps->tdAlpha = dp;
00494  dp = Ps->dTheta - Ps->sdTheta;
00495  if(dp < -180.0)dp += 360.0;
00496  if(dp >  180.0)dp -= 360.0;
00497  dp *= ratio;
00498  dp += Ps->sdTheta;
00499  if(dp < -180.0)dp += 360.0;
00500  if(dp >  180.0)dp -= 360.0;
00501  Ps->tdTheta = dp;
00502  VECSUB(Ps->pin,Ps->spin,dv)
00503  VECSCALE(ratio,dv,dv)
00504  VECSUM(Ps->spin,dv,Ps->tpin)
00505  Ps->tsx=(Ps->sx-Ps->ssx)*ratio+Ps->ssx;
00506  Ps->tsy=(Ps->sx-Ps->ssy)*ratio+Ps->ssy;
00507  Ps->tsz=(Ps->sx-Ps->ssz)*ratio+Ps->ssz;
00508 }
00509 
00510 static void DrawParticleSystemGL(BOOL clip, ParticleSystem *Ps){ // Draw the current state of a speciifc particle system - i.e. where are all the particles
00511  int np,i;
00512  Particle *p;
00513  GLfloat xc,yc,zc;
00514  GLfloat psize;
00515  np=Ps->NumP;
00516  if(np < 1 || Ps->particles == NULL)return;
00517  if(R_Nground > 0){
00518    GLdouble GroundClip[4];
00519    GroundClip[0]=-Ground.n[0]; GroundClip[1]=-Ground.n[2]; GroundClip[2]=Ground.n[1];
00520    GroundClip[3]=DOT(Ground.n,Ground.p)*GlobalScale; 
00521    glEnable(GL_CLIP_PLANE0); 
00522    glClipPlane(GL_CLIP_PLANE0,GroundClip);
00523  }
00524  glBindTexture(GL_TEXTURE_2D,g_particle_textures[Ps->iid]);
00525  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00526  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00527  glEnable(GL_BLEND);
00528  if(Ps->blend_type == 1)glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
00529  else glBlendFunc(GL_SRC_ALPHA,GL_ONE);
00530  glDepthMask(GL_FALSE);
00531  glBegin(GL_QUADS);
00532  for(i=0;i<np;i++){  // render all the particles in the particle system 
00533    p=&Ps->particles[i];
00534    if(p->fAge < 0.0)continue;    // don't render particles that are not active
00535    if(p->pfx[1] < 0.0)continue;  // don't render particles behind viewpoint
00536    glColor4f(p->c[0],p->c[1],p->c[2],p->fAlpha);  //   glColor4f(p->c[0],p->c[1],p->c[2],2.0);
00537    xc =  (p->pfx[0])*GlobalScale;
00538    yc =  (p->pfx[2])*GlobalScale;
00539    zc = -(p->pfx[1])*GlobalScale;
00540    psize=p->fSize*SIZE_SCALE*PARTICLE_SCALE/p->pfx[1]*Ps->sx*Ps->fSizeScale;
00541    glTexCoord2f(1.0f, 1.0f); glVertex3f(xc+psize,  yc+psize, zc); // Top Right 
00542    glTexCoord2f(0.0f, 1.0f); glVertex3f(xc-psize,  yc+psize, zc); // Top Left
00543    glTexCoord2f(0.0f, 0.0f); glVertex3f(xc-psize,  yc-psize, zc); // Bottom left
00544    glTexCoord2f(1.0f, 0.0f); glVertex3f(xc+psize,  yc-psize, zc); // Bottom right
00545  }
00546  glEnd();
00547  glDepthMask(GL_TRUE);
00548  glDisable(GL_BLEND);
00549  glBindTexture(GL_TEXTURE_2D,0);
00550  if(R_Nground > 0)glDisable(GL_CLIP_PLANE0);
00551 }
00552 
00553 void RenderParticlesGL(BOOL clip){
00554  int i;
00555  for(i=0;i<Nparticles;i++){  // for the particle systems
00556    DrawParticleSystemGL(clip,&(ParticleS[i]));
00557  }
00558 }
00559 
00560 static void DrawParticleSystem(ParticleSystem *Ps){ // Draw the current particle system as it is.
00561  int np,i,ix,iy;
00562  Particle *p;
00563  GLfloat xc,yc,zc;
00564  GLfloat psize;
00565  fullscreenbuffer *S;
00566  float *Z;
00567  double Xscale,Yscale,xxl,yyt,xxr,yyb;
00568  np=Ps->NumP;    // number of particles to be rendered
00569  if(np < 1 || Ps->particles == NULL)return;
00570  S=FullScreenBuffer;
00571  Z=fszBuffer;
00572  Xscale=scalex; Yscale=scaley;
00573  if(anti_alias == LOW)   {Xscale /= 2;}
00574  if(anti_alias == MEDIUM){Xscale /= 2; Yscale /= 2;}
00575  if(anti_alias == HIGH)  {Xscale /= 3; Yscale /= 2;}
00576  if(anti_alias == ULTRA) {Xscale /= 3; Yscale /= 3;}
00577  for(i=0;i<np;i++){
00578    p=&Ps->particles[i];
00579    if(p->fAge < 0.0)continue;    // don't render particles that are not active
00580    if(p->pfx[1] < 0.0)continue;  // don't render particles behind viewpoint
00581    xc =  (p->pfx[0]);
00582    yc =  (p->pfx[1]);
00583    zc =  (p->pfx[2]);
00584    psize=p->fSize*4.8*PARTICLE_SCALE*Ps->sx*Ps->fSizeScale;  // 4.5 is to make particles same size as GPU version
00585    xxl=(double)ResolutionX/2.0 + (Xscale*(xc-psize)/yc);
00586    yyt=(double)ResolutionY/2.0 - (Yscale*(zc+psize)/yc);
00587    xxr=(double)ResolutionX/2.0 + (Xscale*(xc+psize)/yc);
00588    yyb=(double)ResolutionY/2.0 - (Yscale*(zc-psize)/yc);
00589    // the software renderer has to blend the particle image into the output buffer - it has to 
00590    // take account of the depth buffer so that the particles can appear to move behind other objects.
00591    // the GPU renderer does this naturally.)
00592    BlendFrameBufferParticle(xxl,yyt,xxr,yyb,yc,Ps->iid,Ps->blend_type,p,S,Z);
00593  }
00594 }
00595 
00596 static void BlendFrameBufferPixel(long ix, long iy, double f, double z, double r, double g, double b, double a,
00597                                   fullscreenbuffer *S, float *Z, long type){
00598  double R,G,B;
00599  if(ix>=0 && ix<ResolutionX && iy>=0 && iy<ResolutionY){
00600    if((float)z<*(Z+(iy*(ResolutionX))+ix)){
00601      R=(double)( (S+(iy*(ResolutionX))+ix)->R);
00602      G=(double)( (S+(iy*(ResolutionX))+ix)->G);
00603      B=(double)( (S+(iy*(ResolutionX))+ix)->B);
00604      if(type == 1){ // blend
00605        R=min(255.0, R*(1.0-a) + 255.0*r*f*a); 
00606        G=min(255.0, G*(1.0-a) + 255.0*g*f*a);
00607        B=min(255.0, B*(1.0-a) + 255.0*b*f*a);
00608      }
00609      else{ // burn
00610        R=min(255.0, R + 255.0*r*f*a); 
00611        G=min(255.0, G + 255.0*g*f*a);
00612        B=min(255.0, B + 255.0*b*f*a);
00613      }
00614      (S+(iy*(ResolutionX))+ix)->R=(unsigned char)R;
00615      (S+(iy*(ResolutionX))+ix)->G=(unsigned char)G;
00616      (S+(iy*(ResolutionX))+ix)->B=(unsigned char)B;
00617 //        *(Z+(iy*(ResolutionX))+ix)=Yview;  /*update the Z-buffer with the new depth value*/
00618      }
00619  }
00620 }
00621 
00622 static void BlendFrameBufferParticle(double xxl, double yyt, double xxr, double yyb,
00623                                 double z, long pid, long blend_type, Particle *p, fullscreenbuffer *S, float *Z){
00624  long i,j,ix,iy,xin;
00625  long idx,idy;
00626  double dx,dy,cr,cg,cb,ca,cr0,cg0,cb0,ca0;
00627  unsigned char *image,*simage,*si;
00628  dx=(xxr-xxl);
00629  dy=(yyb-yyt);
00630  idy=(long)dy+1;
00631  idx=(long)dx+1;
00632  dx=xxr-floor(xxr); dy=yyt-floor(yyt);
00633  if((image=ParticleImages[pid]) == NULL)return;
00634  xin=ParticleImageSize[pid];
00635  if(ParticleBits[pid]){ // 4 bits per pixel
00636    simage=(unsigned char *)X__Malloc(idx*idy*4);
00637    if(simage == NULL)return;
00638    ScaleImageBuffer4(xin,xin,image,idx,idy,simage);
00639   }
00640  else{
00641    simage=(unsigned char *)X__Malloc(idx*idy*3);
00642    if(simage == NULL)return;
00643    ScaleImageBuffer3(xin,xin,image,idx,idy,simage);
00644  }
00645  cr0=p->c[0]/255.0;  cg0=p->c[1]/255.0; cb0=p->c[2]/255.0; ca0=p->fAlpha;
00646  si=simage;
00647  iy=(long)yyt; for(i=0;i<idy;i++){
00648    ix=(long)xxl; for(j=0;j<idx;j++){
00649      cr = cr0*(double)(*si++); cg = cg0*(double)(*si++); cb = cb0*(double)(*si++);
00650      if(ParticleBits[pid]) ca = ca0*(double)(*si++)/255.0; else ca=ca0;
00651      BlendFrameBufferPixel(ix,iy,(1.0-dx)*(1.0-dy),z,cr,cg,cb,ca,S,Z,blend_type);
00652      BlendFrameBufferPixel(ix+1,iy,(dx)*(1.0-dy),z,cr,cg,cb,ca,S,Z,blend_type);
00653      BlendFrameBufferPixel(ix,iy+1,(1.0-dx)*(dy),z,cr,cg,cb,ca,S,Z,blend_type);
00654      BlendFrameBufferPixel(ix+1,iy+1,(dx)*(dy),z,cr,cg,cb,ca,S,Z,blend_type);
00655      ix++;
00656    }
00657    iy++;
00658  }
00659  if(simage != NULL)X__Free(simage);
00660 }
00661 
00662 
00663 void RenderParticles(void){  // render into frame buffer 
00664  int i;
00665  for(i=0;i<Nparticles;i++){
00666    DrawParticleSystem(&(ParticleS[i]));
00667  }
00668 }
00669 
00670 
00672 #if 0
00673    if ((long)xx>=0 && (long)xx<ResolutionX && (long)yy>=0 && (long)yy<ResolutionY){
00674  // glBindTexture(GL_TEXTURE_2D,g_particle_textures[Ps->iid]);
00675 //   glColor4f(p->c[0],p->c[1],p->c[2],p->fAlpha);  //   glColor4f(p->c[0],p->c[1],p->c[2],2.0);
00676 //   glTexCoord2f(1.0f, 1.0f); glVertex3f(xc+psize,  yc+psize, zc); // Top Right 
00677 //   glTexCoord2f(0.0f, 1.0f); glVertex3f(xc-psize,  yc+psize, zc); // Top Left
00678 //   glTexCoord2f(0.0f, 0.0f); glVertex3f(xc-psize,  yc-psize, zc); // Bottom left
00679 //   glTexCoord2f(1.0f, 0.0f); glVertex3f(xc+psize,  yc-psize, zc); // Bottom right
00680      ix=(long)xx;
00681      iy=(long)yy;
00682      if((float)yc<*(Z+(iy*(ResolutionX))+ix)){
00683         (S+(iy*(ResolutionX))+ix)->R=255;
00684         (S+(iy*(ResolutionX))+ix)->G=255;
00685         (S+(iy*(ResolutionX))+ix)->B=255;
00686 //        *(Z+(iy*(ResolutionX))+ix)=Yview;  /*update the Z-buffer with the new depth value*/
00687      }
00688    }
00689 #endif
00690 
00691 #if 0
00692  //                   bottom                 top                back               front
00693  GLfloat x[16]={-1.0, 1.0, 1.0,-1.0,  -1.0, 1.0, 1.0,-1.0,   -1.0, 1.0, 1.0,-1.0,  -1.0, 1.0, 1.0,-1.0};
00694  GLfloat y[16]={-1.0,-1.0, 1.0, 1.0,  -1.0,-1.0, 1.0, 1.0,   -1.0,-1.0,-1.0,-1.0,   1.0, 1.0, 1.0, 1.0}; 
00695  GLfloat z[16]={-1.0,-1.0,-1.0,-1.0,   1.0, 1.0, 1.0, 1.0,   -1.0,-1.0, 1.0, 1.0,  -1.0,-1.0, 1.0, 1.0};
00696  glBegin(GL_QUADS);
00697  glColor4ub(0,255,255,255);
00698  for(i=0;i<4*4;i++){
00699  glVertex3f(  (x[i]*PARTICLE_SCALE+Ps->p[0])*GlobalScale,
00700               (z[i]*PARTICLE_SCALE+Ps->p[2])*GlobalScale,
00701              -(y[i]*PARTICLE_SCALE+Ps->p[1])*GlobalScale);
00702 
00703  }
00704  glEnd();
00705 
00706  glPointSize(4.0);
00707  glBegin(GL_POINTS);
00708  glColor4ub(0,255,255,255);
00709  for(i=0;i<np;i++){
00710   p=&Ps->particles[i];
00711   if(p->fAge < 0.0)continue;
00712  // glVertex3f(  (p->p[0]*PARTICLE_SCALE+Ps->p[0])*GlobalScale,
00713  //              (p->p[2]*PARTICLE_SCALE+Ps->p[2])*GlobalScale,
00714  //             -(p->p[1]*PARTICLE_SCALE+Ps->p[1])*GlobalScale);
00715   glVertex3f(  (p->pfx[0])*GlobalScale,
00716                (p->pfx[2])*GlobalScale,
00717               -(p->pfx[1])*GlobalScale);
00718  }
00719  glEnd();
00720 
00722 
00723                                 //this uses spherical coordinates to randomize the velocity vector ( or the direction ) of the m_rParticles
00724                                 m_rParticles[i].m_vVelocity.y = static_cast<float>(cos( RandomPitch ));
00725                                 m_rParticles[i].m_vVelocity.x = static_cast<float>(sin(RandomPitch) * cos(RandomYaw));
00726                                 m_rParticles[i].m_vVelocity.z = static_cast<float>(sin(RandomPitch) * sin(RandomYaw));
00727 
00728                                 /*
00729                                 // Velocity at this point is just a direction (normalized vector ) and needs to be multiplied by 
00730                                 // the speed component to be a true velocity
00731                                 float fNewSpeed = m_fSpeed + RANDOM_NUM * m_fSpeedVar;
00732                                 Clamp( fNewSpeed, MIN_SPEED, MAX_SPEED );
00733                                 */
00734 
00735                                 // Multiply Velocity by speed
00736                                 m_rParticles[i].m_vVelocity.x *= m_fSpeed ;
00737                                 m_rParticles[i].m_vVelocity.y *= m_fSpeed ;
00738                                 m_rParticles[i].m_vVelocity.z *= m_fSpeed ;
00739 
00740 
00741 /*
00742                                 m_rParticles[i].m_vVelocity.y = (0.5f-RANDOM_NUM)* RANDOM_NUM;// * m_fSpeedVar;
00743                                 m_rParticles[i].m_vVelocity.x = (0.5f-RANDOM_NUM)* RANDOM_NUM;// * m_fSpeedVar;
00744                                 m_rParticles[i].m_vVelocity.z = (0.5f-RANDOM_NUM)* RANDOM_NUM;// * m_fSpeedVar;
00745 
00746                                 m_rParticles[i].m_vVelocity.x *= m_fSpeed ;
00747                                 m_rParticles[i].m_vVelocity.y *= m_fSpeed ;
00748                                 m_rParticles[i].m_vVelocity.z *= m_fSpeed ;
00749 
00750 */
00751                                 // let the m_rParticles know who it's Daddy is
00752 
00753 
00754 //   fprintf(debug,"Particle Age=%lf  Alpha=%lf  Lifetime=%lf deltaT=%lf  deltaAlpha=%lf\n",
00755 //   p->fAge,p->fAlpha,p->fLifetime,fTimeDelta,p->fAlphaDelta);
00756 //   fprintf(debug,"velocity %lf %lf %lf\n",p->v[0],p->v[1],p->v[2]);
00757 //   fprintf(debug,"gravity %lf %lf %lf\n",p->g[0],p->g[1],p->g[2]);
00758 
00759 // defaults
00760 pPS->vColorStart[0] = 0.48f; 
00761 pPS->vColorStart[1] = 0.42f; 
00762 pPS->vColorStart[2] = 0.10f; 
00763 pPS->vColorVar[0] = 0.15f; 
00764 pPS->vColorVar[1] = 0.15f; 
00765 pPS->vColorVar[2] = 0.15f; 
00766 pPS->vColorEnd[0] = 0.04f; 
00767 pPS->vColorEnd[1] = 0.22f; 
00768 pPS->vColorEnd[2] = 0.81f; 
00769 pPS->fAlphaStart = 0.92f; 
00770 pPS->fAlphaVar   = 0.14f; 
00771 pPS->fAlphaEnd   = 0.14f; 
00772 pPS->fSizeStart  = 1.04f; 
00773 pPS->fSizeVar    = 0.04f; 
00774 pPS->fSizeEnd    = 1.08f; 
00775 pPS->fSpeed      = 3.00f; 
00776 pPS->fSpeedVar   = 0.00f; 
00777 pPS->fTheta      = 0.20f; 
00778 pPS->fLifeTime   = 0.60f; 
00779 pPS->fLifeVar    = 0.10f; 
00780 pPS->vGravityStart[0] = 0.00f; 
00781 pPS->vGravityStart[1] = 0.00f; 
00782 pPS->vGravityStart[2] = 0.00f; 
00783 pPS->vGravityEnd[0]= 0.00f; 
00784 pPS->vGravityEnd[1]= 0.00f; 
00785 pPS->vGravityEnd[2]= 0.00f; 
00786 pPS->fGravityVar   = 0.00f; 
00787 pPS->fSizeScale    = 1.0;
00788 pPS->uParticlesPerSec = 20;  // related to NumP  - should be the default
00789 pPS->NumP=60;                // should be enougg for all particles to be alive   no/sec * lifetime    
00791 
00792 #endif
00793 

Generated on Sun Apr 27 14:20:13 2014 for OpenFX by  doxygen 1.5.6