00001
00002
00003
00004
00005
00006 #include "Particles.h"
00007 #include "genesis.h"
00008 #include "ram.h"
00009 #include "errorlog.h"
00010 #include "procutil.h"
00011 #include "gebmutil.h"
00012 #include "vec3d.h"
00013 #include <stdlib.h>
00014 #include <string.h>
00015 #include <assert.h>
00016 #include <math.h>
00017
00018 #ifdef DO_TIMER
00019 #include "timer.h"
00020
00021 TIMER_VARS(Particles);
00022 #endif
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 static const char * Params_Oil = "100, 1, oil, 1, 1, wrap, t, 0, 1, 0, f,"
00050 "0.5, 0.5, 0.5, 0,0,0, 1.0, 0, "
00051 "0,0,0, 0.3,0.2,0, 0, 99,0, 0.01,0.0, "
00052 "end";
00053 static const char * Params_Jet = "200, 1, fire, 1, 1, hard, f, t, 100, t, 0, 1, 0, 0.5, 0, 0.5,"
00054 "0.5, 0, 0.5, 0,0.6,0, 0.03, 0, "
00055 "0,0,0, 0.5,0.4,0, 0, 99, 0, 0.01,0.0, "
00056 "end)";
00057 static const char * Params_Steam = "50, 1, steam, 2, 1, hard, f, f, "
00058 "0.5, 0, 0.5, 0,0.25,0, 0.7, 0, "
00059 "0,0,0, 0.15,0.10,0,0.3,99,0,0.02,0.0005, "
00060 "end";
00061 static const char * Params_Explosion = "300, 1,fire, 1, 1, bounce, f, f,"
00062 "0.5, 0.5, 0.5, 0,0,0, 0.1, 0,"
00063 "0,0,0, 0.3,0.3,0.3, 0.05, 0, 0, 0.01, 0.0003,"
00064 "end)";
00065
00066 #define DefaultParams Params_Steam
00067
00068 #include "gebmutil.h"
00069
00070 #define NUM_CLEAR_POINTS (0)
00071
00072
00073
00074
00075
00076 #define BM_CREATE_WIDTH (128)
00077 #define BM_CREATE_HEIGHT (128)
00078
00079
00080
00081 #define PIXEL_INDEX(c,s,nc) (((s)*(nc)) + (c))
00082 #define PIXEL_SHADE(pel,nc) ((pel)/(nc))
00083 #define PIXEL_COLOR(pel,nc) ((pel)%(nc))
00084
00085 typedef void (*CoordCapperFunc) (float *x,float *v, int size);
00086 typedef void (*PixelRGBAFunc) (Procedural *Proc,int c,int s,int *R,int *G,int *B,int *);
00087
00088 typedef struct
00089 {
00090 float p[3],
00091 v[3];
00092 int color,shade;
00093 float DeathTime,CurDeathTime;
00094 float Drag;
00095 } Particle;
00096
00097 typedef struct
00098 {
00099 Particle Base;
00100 Particle Random;
00101 float RandomVMagnitude;
00102 float Delay,CurTime;
00103 } ParticleSource;
00104
00105 typedef struct Procedural
00106 {
00107 geBitmap * Bitmap;
00108 Particle * Particles;
00109 ParticleSource * Sources;
00110
00111 int NumActiveParticles;
00112 int SizeX,SizeY,SizeZ;
00113 geBitmap_Info BmInfo;
00114
00115 int NumParticles,NumSources;
00116 int NumColors,NumShades;
00117 int NumSmoothes,SmoothRadius;
00118 geBoolean SmoothWrap;
00119
00120 CoordCapperFunc Capper;
00121 PixelRGBAFunc PixelRGBA;
00122
00123 geBoolean DoMagnetic;
00124 geVec3d MagneticField;
00125
00126 geBoolean DoAttractor;
00127 geBoolean AttractorIsAxis;
00128 geVec3d AttractorPos,AttractorAxis;
00129 float AttractorStrength;
00130 } Procedural;
00131
00132
00133
00134 geBoolean Particles_InitBitmap(geBitmap **ppBitmap);
00135 geBoolean Particles_InitPalette(Procedural * Proc);
00136 void Particles_Destroy(Procedural * Proc);
00137
00138 Particle * Particles_NewParticle(Procedural *Proc);
00139 void Particles_EmitSources(Procedural *Proc,float time);
00140 void Particles_MoveParticles(Procedural * Proc,float time);
00141 geBoolean Particles_Draw(Procedural *Proc);
00142
00143 void Capper_Wrap(float *x,float *v, int size);
00144 void Capper_Hard(float *x,float *v, int size);
00145 void Capper_Bounce(float *x,float *v, int size);
00146
00147 void PixelRGBA_OilColor(Procedural *Proc,int c,int s,int *R,int *G,int *B,int *A);
00148 void PixelRGBA_FireColor(Procedural *Proc,int c,int s,int *R,int *G,int *B,int *A);
00149 void PixelRGBA_OpaqueFireColor(Procedural *Proc,int c,int s,int *R,int *G,int *B,int *A);
00150 void PixelRGBA_SteamColor(Procedural *Proc,int c,int s,int *R,int *G,int *B,int *A);
00151
00152
00153
00154 #define ABS(x) ( (x) < 0 ? (-(x)) : (x) )
00155 #define minmax(x,lo,hi) ( (x)<(lo)?(lo):( (x)>(hi)?(hi):(x)) )
00156 #define putminmax(x,lo,hi) x = minmax(x,lo,hi)
00157
00158 static const char * strbreakers = " ,`\t\n\r\034\009";
00159
00160 #define nextparam(pstr) do { pstr = strtok(NULL,strbreakers); if ( ! pstr ) { Particles_Destroy(Proc); geErrorLog_AddString(-1,"Particle Procedural : params insufficient", NULL); return NULL; } } while(0)
00161 #define getint(pstr) atol(pstr); nextparam(pstr);
00162 #define getbool(pstr) ( toupper(*pstr) == 'T' ? GE_TRUE : (toupper(*pstr) == 'F' ? GE_FALSE : (atol(pstr)) ) ); nextparam(pstr);
00163 #define getfloat(pstr) (float)atof(pstr); nextparam(pstr);
00164 #define getvec(pstr,pvec) do { ((geVec3d *)pvec)->X = getfloat(pstr); ((geVec3d *)pvec)->Y = getfloat(pstr); ((geVec3d *)pvec)->Z = getfloat(pstr); } while(0)
00165 #define scalevec(pvec) do { ((geVec3d *)pvec)->X *= Proc->SizeX; ((geVec3d *)pvec)->Y *= Proc->SizeY; ((geVec3d *)pvec)->Z *= Proc->SizeZ; } while(0)
00166 #define absvec(pvec) do { ((geVec3d *)pvec)->X = ABS(((geVec3d *)pvec)->X); ((geVec3d *)pvec)->Y = ABS(((geVec3d *)pvec)->Y); ((geVec3d *)pvec)->Z = ABS(((geVec3d *)pvec)->Z); } while(0)
00167 #define matchstr(str,vs) ( strnicmp(str,vs,strlen(vs)) == 0 )
00168
00169
00170
00171 Procedural * Particles_Create(geBitmap **ppBitmap, const char *InputParams)
00172 {
00173 Procedural * Proc;
00174 int i;
00175 char ParamWork[8192],*pstr;
00176
00177 if ( ! (Proc = geRam_AllocateClear(sizeof(Procedural))) )
00178 return NULL;
00179
00180
00181
00182 if ( strlen(InputParams) < 20 )
00183 {
00184 strcpy(ParamWork,DefaultParams);
00185 geErrorLog_AddString(-1,"Particle Procedural : no params : using default ", NULL);
00186 }
00187 else
00188 {
00189 strcpy(ParamWork,InputParams);
00190 }
00191
00192 pstr = strtok(ParamWork,strbreakers);
00193
00194 Proc->NumParticles = getint(pstr);
00195 Proc->NumSources = getint(pstr);
00196
00197
00198
00199 if ( ! Particles_InitBitmap(ppBitmap) )
00200 goto fail;
00201 Proc->Bitmap = *ppBitmap;
00202
00203 Proc->SizeX = geBitmap_Width(Proc->Bitmap);
00204 Proc->SizeY = geBitmap_Height(Proc->Bitmap);
00205 geBitmap_GetInfo(Proc->Bitmap,&(Proc->BmInfo),NULL);
00206 Proc->SizeZ = min(Proc->SizeX,Proc->SizeY);
00207
00208
00209
00210 Proc->Particles = geRam_AllocateClear(Proc->NumParticles * sizeof(Particle));
00211 if (! (Proc->Particles) )
00212 goto fail;
00213 for(i=0;i<Proc->NumParticles;i++)
00214 {
00215 Proc->Particles[i].shade = -1;
00216 }
00217 Proc->NumActiveParticles = 0;
00218
00219
00220
00221 Proc->Sources = geRam_AllocateClear(Proc->NumSources * sizeof(ParticleSource));
00222 if (! (Proc->Sources) )
00223 goto fail;
00224
00225
00226
00227
00228
00229 if ( matchstr(pstr,"oil") )
00230 {
00231 nextparam(pstr);
00232 Proc->NumColors = Proc->NumShades = 16;
00233 Proc->PixelRGBA = PixelRGBA_OilColor;
00234 }
00235 else if ( matchstr(pstr,"fire") )
00236 {
00237 nextparam(pstr);
00238 Proc->NumColors = 1;
00239 Proc->NumShades = 256;
00240 Proc->PixelRGBA = PixelRGBA_FireColor;
00241 }
00242 else if ( matchstr(pstr,"opaquefire") )
00243 {
00244 nextparam(pstr);
00245 Proc->NumColors = 1;
00246 Proc->NumShades = 256;
00247 Proc->PixelRGBA = PixelRGBA_OpaqueFireColor;
00248 }
00249 else if ( matchstr(pstr,"steam") )
00250 {
00251 nextparam(pstr);
00252 Proc->NumColors = 1;
00253 Proc->NumShades = 256;
00254 Proc->PixelRGBA = PixelRGBA_SteamColor;
00255 }
00256 else
00257 {
00258 Proc->NumColors = getint(pstr);
00259 Proc->NumShades = getint(pstr);
00260 Proc->PixelRGBA = PixelRGBA_OilColor;
00261
00262
00263 }
00264
00265 if ( (Proc->NumColors * Proc->NumShades) < 256 )
00266 {
00267 Proc->NumColors = min(Proc->NumColors,256);
00268 Proc->NumShades = 256 / Proc->NumColors;
00269 }
00270
00271 Proc->NumSmoothes = getint(pstr);
00272 Proc->SmoothRadius = getint(pstr);
00273
00274 if ( matchstr(pstr,"bounce") )
00275 {
00276 Proc->Capper = Capper_Bounce;
00277 Proc->SmoothWrap = GE_FALSE;
00278 }
00279 else if ( matchstr(pstr,"wrap") )
00280 {
00281 Proc->Capper = Capper_Wrap;
00282 Proc->SmoothWrap = GE_TRUE;
00283 }
00284 else if ( matchstr(pstr,"hard") )
00285 {
00286 Proc->Capper = Capper_Hard;
00287 Proc->SmoothWrap = GE_FALSE;
00288 }
00289 else
00290 {
00291 goto fail;
00292 }
00293 nextparam(pstr);
00294
00295 Proc->DoMagnetic = getbool(pstr);
00296 if ( Proc->DoMagnetic )
00297 {
00298 getvec(pstr,&(Proc->MagneticField));
00299 }
00300
00301 Proc->DoAttractor = getbool(pstr);
00302 if ( Proc->DoAttractor )
00303 {
00304 Proc->AttractorStrength = getfloat(pstr);
00305 Proc->AttractorIsAxis = getbool(pstr);
00306 if ( Proc->AttractorIsAxis )
00307 {
00308 getvec(pstr,&(Proc->AttractorAxis));
00309 geVec3d_Normalize(&(Proc->AttractorAxis));
00310 }
00311 getvec(pstr,&(Proc->AttractorPos));
00312 scalevec(&(Proc->AttractorPos));
00313 }
00314
00315
00316
00317 if ( ! Particles_InitPalette(Proc) )
00318 goto fail;
00319
00320 for(i=0;i< Proc->NumSources; i++)
00321 {
00322 ParticleSource * pSource;
00323 Particle * pParticle;
00324
00325 pSource = Proc->Sources + i;
00326
00327 pParticle = &(pSource->Base);
00328
00329 getvec(pstr,pParticle->p);
00330 getvec(pstr,pParticle->v);
00331 scalevec(pParticle->p);
00332 scalevec(pParticle->v);
00333 pParticle->DeathTime = getfloat(pstr);
00334 pParticle->color = getint(pstr);
00335 pParticle->shade = Proc->NumShades - 1;
00336 pParticle->CurDeathTime = 0.0f;
00337
00338 pParticle = &(pSource->Random);
00339
00340 getvec(pstr,pParticle->p);
00341 getvec(pstr,pParticle->v);
00342 scalevec(pParticle->p);
00343 scalevec(pParticle->v);
00344 absvec(pParticle->p);
00345 absvec(pParticle->v);
00346
00347 pParticle->DeathTime = getfloat(pstr);
00348
00349 pParticle->color = getint(pstr);
00350 pParticle->shade = getint(pstr);
00351 pParticle->CurDeathTime = 0.0f;
00352
00353 pSource->RandomVMagnitude = geVec3d_Normalize( (geVec3d *) (pParticle->v) );
00354
00355 pSource->Delay = getfloat(pstr);
00356 pSource->Base.Drag = getfloat(pstr);
00357 pSource->CurTime = pSource->Delay;
00358 }
00359
00360 if ( strnicmp(pstr,"end",3) != 0 )
00361 {
00362
00363 }
00364
00365 #ifdef DO_TIMER
00366 timerFP = fopen("q:\\timer.log","at+");
00367 Timer_Start();
00368 #endif
00369
00370 return Proc;
00371
00372 fail:
00373
00374 Particles_Destroy(Proc);
00375 return NULL;
00376 }
00377
00378
00379
00380 void Particles_Destroy(Procedural * Proc)
00381 {
00382 if ( ! Proc )
00383 return;
00384
00385 if ( Proc->Bitmap )
00386 geBitmap_Destroy(&(Proc->Bitmap));
00387 if ( Proc->Particles )
00388 geRam_Free(Proc->Particles);
00389 if ( Proc->Sources )
00390 geRam_Free(Proc->Sources);
00391
00392 #ifdef DO_TIMER
00393 Timer_Stop();
00394 if ( timerFP )
00395 {
00396 TIMER_REPORT(Particles);
00397 }
00398 #endif
00399
00400 geRam_Free(Proc);
00401 }
00402
00403
00404
00405 geBoolean Particles_Animate(Procedural * Proc,float time)
00406 {
00407
00408 #ifdef DO_TIMER
00409 TIMER_P(Particles);
00410 #endif
00411
00412 Particles_EmitSources(Proc,time);
00413
00414 Particles_MoveParticles(Proc,time);
00415
00416 Particles_Draw(Proc);
00417
00418 #ifdef DO_TIMER
00419 TIMER_Q(Particles);
00420 TIMER_COUNT();
00421 #endif
00422
00423 return GE_TRUE;
00424 }
00425
00426
00427
00428 Particle * Particles_NewParticle(Procedural *Proc)
00429 {
00430 Particle * pP;
00431 int p;
00432 pP = Proc->Particles;
00433 for(p= Proc->NumParticles;p--;pP++)
00434 {
00435 if ( pP->shade < 0 )
00436 {
00437 Proc->NumActiveParticles++;
00438 return pP;
00439 }
00440 }
00441 pP = NULL;
00442 assert(pP);
00443 return pP;
00444 }
00445 void Particles_DeleteParticle(Procedural *Proc,Particle *pP)
00446 {
00447 Particle * pPNew;
00448 pPNew = Proc->Particles + (Proc->NumActiveParticles - 1);
00449 Proc->NumActiveParticles --;
00450 *pP = *pPNew;
00451 pPNew->shade = -1;
00452 }
00453
00454 void Particles_EmitSources(Procedural *Proc,float time)
00455 {
00456 int cnt;
00457 ParticleSource * pSource;
00458 Particle *pP,*pR;
00459
00460 pSource = Proc->Sources;
00461 for(cnt=Proc->NumSources;cnt--;pSource++)
00462 {
00463 pSource->CurTime += time;
00464 while ( pSource->CurTime > pSource->Delay &&
00465 Proc->NumActiveParticles < Proc->NumParticles )
00466 {
00467 float rv,t;
00468
00469 pSource->CurTime -= pSource->Delay;
00470
00471 pP = Particles_NewParticle(Proc);
00472 *pP = pSource->Base;
00473 pR = &(pSource->Random);
00474 rv = ProcUtil_RandSignedFloat( pSource->RandomVMagnitude );
00475 t = ProcUtil_RandSignedUnitFloat();
00476 pP->v[0] += rv * pR->v[0] * t;
00477 t = ProcUtil_RandSignedUnitFloat();
00478 pP->v[1] += rv * pR->v[1] * t;
00479 t = ProcUtil_RandSignedUnitFloat();
00480 pP->v[2] += rv * pR->v[2] * t;
00481 pP->p[0] += ProcUtil_RandSignedFloat(pR->p[0]);
00482 pP->p[1] += ProcUtil_RandSignedFloat(pR->p[1]);
00483 pP->p[2] += ProcUtil_RandSignedFloat(pR->p[2]);
00484 pP->color += ProcUtil_RandSigned(pR->color);
00485 pP->shade += ProcUtil_RandSigned(pR->shade);
00486 putminmax(pP->color,0,Proc->NumColors - 1);
00487 putminmax(pP->shade,0,Proc->NumShades - 1);
00488
00489 assert( geVec3d_IsValid((geVec3d *)pP->p) );
00490 assert( geVec3d_IsValid((geVec3d *)pP->v) );
00491 }
00492 }
00493
00494 }
00495
00496 void Particles_MoveParticles(Procedural * Proc,float time)
00497 {
00498 int cnt;
00499 Particle * pP;
00500
00501 pP = Proc->Particles;
00502 for(cnt=0;cnt<Proc->NumActiveParticles;cnt++,pP++)
00503 {
00504 float mul,vsqr;
00505
00506 assert( pP->shade >= 0 );
00507 assert( geVec3d_IsValid((geVec3d *)pP->p) );
00508 assert( geVec3d_IsValid((geVec3d *)pP->v) );
00509
00510 pP->CurDeathTime += time;
00511 if ( pP->CurDeathTime > pP->DeathTime )
00512 {
00513 pP->shade -= (Proc->NumShades + 15)>>4;
00514 pP->CurDeathTime -= pP->DeathTime;
00515 }
00516
00517 if ( pP->shade < 0 )
00518 {
00519 Particles_DeleteParticle(Proc,pP);
00520 if ( cnt >= Proc->NumActiveParticles )
00521 break;
00522 }
00523
00524 assert( geVec3d_IsValid((geVec3d *)pP->p) );
00525 assert( geVec3d_IsValid((geVec3d *)pP->v) );
00526
00527 pP->p[0] += pP->v[0] * time;
00528 Proc->Capper( pP->p + 0, pP->v + 0, Proc->SizeX);
00529
00530 pP->p[1] += pP->v[1] * time;
00531 Proc->Capper( pP->p + 1, pP->v + 1, Proc->SizeY);
00532
00533 pP->p[2] += pP->v[2] * time;
00534 Proc->Capper( pP->p + 2, pP->v + 2, Proc->SizeZ);
00535
00536 assert( geVec3d_IsValid((geVec3d *)pP->p) );
00537 assert( geVec3d_IsValid((geVec3d *)pP->v) );
00538
00539 vsqr = geVec3d_LengthSquared((geVec3d *)pP->v);
00540 assert( vsqr >= 0.0f );
00541 if ( vsqr > 100.0f ) vsqr = 100.0f;
00542 mul = vsqr * pP->Drag;
00543 if ( mul > 0.05f ) mul = 0.05f;
00544 pP->v[0] -= pP->v[0] * mul;
00545 pP->v[1] -= pP->v[1] * mul;
00546 pP->v[2] -= pP->v[2] * mul;
00547
00548
00549
00550 assert( geVec3d_IsValid((geVec3d *)pP->p) );
00551 assert( geVec3d_IsValid((geVec3d *)pP->v) );
00552
00553 if ( Proc->DoMagnetic )
00554 {
00555 geVec3d A;
00556
00557 geVec3d_CrossProduct( (geVec3d *) (pP->v) , &(Proc->MagneticField), &A);
00558 pP->v[0] += time * A.X;
00559 pP->v[1] += time * A.Y;
00560 pP->v[2] += time * A.Z;
00561
00562 assert( geVec3d_IsValid((geVec3d *)pP->p) );
00563 assert( geVec3d_IsValid((geVec3d *)pP->v) );
00564 }
00565
00566 if ( Proc->DoAttractor )
00567 {
00568 float ax,ay,az,q;
00569
00570 if ( Proc->AttractorIsAxis )
00571 {
00572 geVec3d Diff;
00573 geVec3d_Subtract( (geVec3d *) pP->p , &(Proc->AttractorPos), &Diff);
00574 q = geVec3d_DotProduct( &(Proc->AttractorAxis), &Diff );
00575 ax = q * Proc->AttractorAxis.X - Diff.X;
00576 ay = q * Proc->AttractorAxis.Y - Diff.Y;
00577 az = q * Proc->AttractorAxis.Z - Diff.Z;
00578 }
00579 else
00580 {
00581 ax = Proc->AttractorPos.X - pP->p[0];
00582 ay = Proc->AttractorPos.Y - pP->p[1];
00583 az = Proc->AttractorPos.Z - pP->p[2];
00584 }
00585
00586 #if 0 // Electric Attractor
00587 q = (float)sqrt(ax*ax + ay*ay + az*az + 1.0);
00588 q = Proc->AttractorStrength * 100.0f * time / (q*q*q);
00589 #else // Spring Attractor
00590 q = Proc->AttractorStrength * time;
00591 #endif
00592 ax *= q;
00593 ay *= q;
00594 az *= q;
00595
00596 pP->v[0] += ax;
00597 pP->v[1] += ay;
00598 pP->v[2] += az;
00599 }
00600
00601 assert( geVec3d_IsValid((geVec3d *)pP->p) );
00602 assert( geVec3d_IsValid((geVec3d *)pP->v) );
00603 }
00604 }
00605
00606 geBoolean Particles_Draw(Procedural *Proc)
00607 {
00608 geBitmap *Lock=NULL;
00609 uint8 *Bits;
00610 int w,h,s,cnt,x,y;
00611 Particle * pP;
00612 uint8 *pBits,pel;
00613
00614 assert(Proc->Bitmap);
00615
00616 geBitmap_SetGammaCorrection(Proc->Bitmap, 1.0f, GE_FALSE);
00617
00618 if ( ! geBitmap_LockForWriteFormat(Proc->Bitmap,&Lock,0,0,GE_PIXELFORMAT_8BIT_PAL) )
00619 goto fail;
00620
00621 if ( ! geBitmap_GetInfo(Lock,&(Proc->BmInfo),NULL) )
00622 goto fail;
00623
00624 if ( Proc->BmInfo.Format != GE_PIXELFORMAT_8BIT_PAL )
00625 goto fail;
00626
00627 Bits = geBitmap_GetBits(Lock);
00628
00629 if ( ! Bits )
00630 goto fail;
00631
00632 w = Proc->BmInfo.Width;
00633 h = Proc->BmInfo.Height;
00634 s = Proc->BmInfo.Stride;
00635
00636 for( cnt = NUM_CLEAR_POINTS; cnt --; )
00637 {
00638 int shade,color;
00639 int nc = Proc->NumColors;
00640 x = ProcUtil_Rand(w);
00641 y = ProcUtil_Rand(h);
00642 pBits = Bits + y*s + x;
00643 shade = PIXEL_SHADE(*pBits,nc);
00644 color = PIXEL_COLOR(*pBits,nc);
00645 shade >>= 1;
00646 *pBits = PIXEL_INDEX(color,shade,nc);
00647 }
00648
00649 for( cnt=Proc->NumActiveParticles, pP = Proc->Particles;
00650 cnt > 0 ;
00651 pP++ )
00652 {
00653 assert( pP->shade >= 0 );
00654
00655 x = (int)(pP->p[0]);
00656 y = (int)(pP->p[1]);
00657 putminmax(x, 1, w-2);
00658 putminmax(y, 1, h-2);
00659 pBits = Bits + (y * s) + x;
00660 pel = PIXEL_INDEX(pP->color,pP->shade,Proc->NumColors);
00661 pBits[0] = pBits[1] = pBits[-1] = pBits[s] = pBits[-s] = pel;
00662
00663 cnt--;
00664 }
00665
00666 for( cnt = Proc->NumSmoothes; cnt--; )
00667 {
00668 if ( ! geBitmapUtil_SmoothBits(&(Proc->BmInfo),Bits,Bits,Proc->SmoothRadius,Proc->SmoothWrap) )
00669 goto fail;
00670 }
00671
00672 if ( ! geBitmap_UnLock(Lock) )
00673 goto fail;
00674
00675 return GE_TRUE;
00676 fail:
00677
00678 if ( Lock ) geBitmap_UnLock(Lock);
00679
00680 return GE_FALSE;
00681 }
00682
00683
00684
00685 geBoolean Particles_InitBitmap(geBitmap **ppBitmap)
00686 {
00687 assert( ppBitmap);
00688 if ( ! *ppBitmap )
00689 {
00690 *ppBitmap = geBitmap_Create(BM_CREATE_WIDTH,BM_CREATE_HEIGHT,1, GE_PIXELFORMAT_8BIT_PAL);
00691 if ( ! *ppBitmap )
00692 return GE_FALSE;
00693 }
00694 else
00695 {
00696 geBitmap_CreateRef(*ppBitmap);
00697 }
00698
00699 if ( ! geBitmap_SetFormat(*ppBitmap,GE_PIXELFORMAT_8BIT_PAL,GE_FALSE,0,NULL) )
00700 return GE_FALSE;
00701
00702 if ( ! geBitmap_ClearMips(*ppBitmap) )
00703 return GE_FALSE;
00704
00705 if ( ! geBitmap_SetPreferredFormat(*ppBitmap,GE_PIXELFORMAT_16BIT_4444_ARGB) )
00706 return GE_FALSE;
00707
00708 if ( ! geBitmapUtil_SetColor(*ppBitmap,0,0,0,0) )
00709 return GE_FALSE;
00710
00711 return GE_TRUE;
00712 }
00713
00714 geBoolean Particles_InitPalette(Procedural * Proc)
00715 {
00716 geBitmap_Info Info;
00717 geBitmap_Palette *Pal;
00718 void * PalData = NULL;
00719 gePixelFormat PalFormat;
00720 int PalSize;
00721
00722 Pal = geBitmap_Palette_Create(GE_PIXELFORMAT_32BIT_ARGB,256);
00723 if ( ! Pal )
00724 goto fail;
00725 if ( ! geBitmap_SetPalette(Proc->Bitmap,Pal) )
00726 goto fail;
00727 geBitmap_Palette_Destroy(&Pal);
00728
00729 if ( ! geBitmap_GetInfo(Proc->Bitmap,&Info,NULL) )
00730 goto fail;
00731
00732 if ( Info.Format != GE_PIXELFORMAT_8BIT_PAL )
00733 goto fail;
00734
00735 if ( ! (Pal = geBitmap_GetPalette(Proc->Bitmap)) )
00736 goto fail;
00737
00738 if ( ! geBitmap_Palette_Lock(Pal,&PalData, &PalFormat, &PalSize) )
00739 goto fail;
00740 if ( PalSize < 256 )
00741 goto fail;
00742
00743 {
00744 int p;
00745 uint8 * PalPtr;
00746 int R,G,B,A;
00747 int c,s;
00748
00749 for(c=0;c<(Proc->NumColors);c++)
00750 {
00751 for(s=0;s<(Proc->NumShades);s++)
00752 {
00753 p = PIXEL_INDEX(c,s,Proc->NumColors);
00754 Proc->PixelRGBA(Proc,c,s,&R,&G,&B,&A);
00755 PalPtr = ((uint8 *)PalData) + p * gePixelFormat_BytesPerPel(PalFormat);
00756 gePixelFormat_PutColor(PalFormat,&PalPtr,R,G,B,A);
00757 }
00758 }
00759 }
00760
00761 PalData = NULL;
00762
00763 if ( ! geBitmap_Palette_UnLock(Pal) )
00764 return GE_FALSE;
00765
00766 return GE_TRUE;
00767
00768 fail:
00769
00770 if ( PalData )
00771 geBitmap_Palette_UnLock(Pal);
00772
00773 return GE_FALSE;
00774
00775 }
00776
00777
00778
00779 void Capper_Wrap(float *x,float *v, int size)
00780 {
00781 if ( *x < 0 )
00782 {
00783 *x += size;
00784 }
00785 else if ( *x >= size )
00786 {
00787 *x -= size;
00788 }
00789 }
00790
00791 void Capper_Hard(float *x,float *v, int size)
00792 {
00793 if ( *x < 0 )
00794 {
00795 *x = 0;
00796 }
00797 else if ( *x >= size )
00798 {
00799 *x = (float)(size - 1);
00800 }
00801 }
00802
00803 void Capper_Bounce(float *x,float *v, int size)
00804 {
00805 if ( *x < 0 )
00806 {
00807 *x = 0;
00808 *v *= -1;
00809 }
00810 else if ( *x >= size )
00811 {
00812 *x = (float)(size - 1);
00813 *v *= -1;
00814 }
00815 }
00816
00817
00818
00819 static Procedural_Table Particles_Table =
00820 {
00821 Procedurals_Version,Procedurals_Tag,
00822 "Particles",
00823 Particles_Create,
00824 Particles_Destroy,
00825 Particles_Animate
00826 };
00827
00828 Procedural_Table * Particles_GetProcedural_Table(void)
00829 {
00830 return &Particles_Table;
00831 }
00832
00833
00834
00835 void PixelRGBA_OilColor(Procedural *Proc,int c,int s,int *R,int *G,int *B,int *A)
00836 {
00837
00838
00839
00840
00841 if ( Proc->NumColors == 1 ) *B = 0;
00842 else *B = (255 * c) / (Proc->NumColors - 1);
00843 *G = *R = 255 - *B;
00844 *A = (255 * s) / (Proc->NumShades - 1);
00845 if ( *A > 200 ) *A = 255;
00846 else *A = (int)(300 * pow((*A)/255.0,0.7));
00847 }
00848
00849 void PixelRGBA_FireColor(Procedural *Proc,int c,int s,int *R,int *G,int *B,int *A)
00850 {
00851 float sfrac;
00852 sfrac = (float)s / (Proc->NumShades - 1);
00853 *R = (int)(255 * pow(sfrac, 0.3));
00854 *G = (int)(255 * pow(sfrac, 0.7));
00855 *B = (int)(128 * pow(sfrac, 3.0));
00856 if ( sfrac > 0.4 ) *A = 255;
00857 else *A = (int)(530 * pow(sfrac, 0.8));
00858 }
00859
00860 void PixelRGBA_OpaqueFireColor(Procedural *Proc,int c,int s,int *R,int *G,int *B,int *A)
00861 {
00862 float sfrac;
00863 sfrac = (float)s / (Proc->NumShades - 1);
00864 *R = (int)(255 * pow(sfrac, 0.3));
00865 *G = (int)(255 * pow(sfrac, 0.7));
00866 *B = (int)(128 * pow(sfrac, 3.0));
00867 *A = min((int)(400 * pow(sfrac, 0.3)),255);
00868 }
00869
00870 void PixelRGBA_SteamColor(Procedural *Proc,int c,int s,int *R,int *G,int *B,int *A)
00871 {
00872 float sfrac;
00873 sfrac = (float)s / (Proc->NumShades - 1);
00874 *A = (int)(255 * pow(sfrac, 0.5));
00875 *R = *G = *B = *A;
00876 }