00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <Assert.h>
00016 #include <Stdlib.h>
00017
00018 #include <Math.h>
00019
00020 #include "Procedural.h"
00021 #include "String.h"
00022 #include "Bitmap.h"
00023 #include "Ram.h"
00024 #include "gebmutil.h"
00025
00026 #define SMOOTH_WRAP GE_FALSE
00027
00028
00029
00030
00031 #define NSMPARTICLES 1024
00032
00033 typedef struct
00034 {
00035
00036 int32 Velocity[3];
00037 int32 Position[3];
00038 } Smoke_Data;
00039
00040 typedef struct Procedural
00041 {
00042 geBitmap *Bitmap;
00043 geBitmap_Info BitmapInfo;
00044
00045 int32 Width;
00046 int32 Height;
00047 int32 Size;
00048
00049
00050 Smoke_Data Smbuf[NSMPARTICLES];
00051
00052 int32 *ZBuffer;
00053 float *ZAge;
00054
00055 int32 NumParticles;
00056 float x, y, z, vx, vy, vz;
00057
00058 int32 PalIndex;
00059 } Procedural;
00060
00061 void Smoke_Destroy(Procedural *Proc);
00062 geBoolean Smoke_Animate(Procedural *Smoke, float ElapsedTime);
00063
00064
00065
00066 void Smoke_FillParticle(Smoke_Data *particle,
00067 float xp,
00068 float yp,
00069 float zp,
00070 float xv,
00071 float yv,
00072 float zv);
00073
00074 geBoolean Smoke_Shade(Procedural *Smoke);
00075
00076 geBoolean Smoke_Update( Procedural *Smoke,
00077 int nparticles,
00078 float xp,
00079 float yp,
00080 float zp,
00081 float xv,
00082 float yv,
00083 float zv,
00084 int lightdir);
00085
00086 int32 Smoke_GetPalIndexFromString(const char *Str);
00087 geBoolean Smoke_InitBitmap(Procedural *Proc, geBitmap **ppBitmap);
00088 geBoolean Smoke_InitPalette(Procedural *Proc);
00089
00090
00091
00092
00093 Procedural *Smoke_Create(geBitmap **Bitmap, const char *StrParms)
00094 {
00095 Procedural *Proc;
00096
00097 assert(Bitmap);
00098
00099
00100 Proc = GE_RAM_ALLOCATE_STRUCT(Procedural);
00101
00102 if (!Proc)
00103 goto ExitWithError;
00104
00105 memset(Proc, 0, sizeof(*Proc));
00106
00107 {
00108 char *Token;
00109 int32 TokenNum;
00110 char Parms[1024];
00111
00112 Proc->PalIndex = 0;
00113
00114 Proc->NumParticles = 128;
00115
00116 Proc->x = 6.0f;
00117 Proc->y = 64.0f;
00118 Proc->z = 25.0f;
00119
00120 Proc->vx = 4.0f;
00121 Proc->vy = 5.0f;
00122 Proc->vz = 1.0f;
00123
00124 strcpy(Parms, StrParms);
00125
00126 TokenNum = 0;
00127
00128 Token = strtok(Parms," \t,+\n\r");
00129
00130 while(Token)
00131 {
00132 switch(TokenNum)
00133 {
00134 case 0:
00135 Proc->PalIndex = Smoke_GetPalIndexFromString(Token);
00136 break;
00137 case 1:
00138 Proc->NumParticles = atoi(Token);
00139 break;
00140 case 2:
00141 Proc->x = (float)atof(Token);
00142 break;
00143 case 3:
00144 Proc->y = (float)atof(Token);
00145 break;
00146 case 4:
00147 Proc->z = (float)atof(Token);
00148 break;
00149 case 5:
00150 Proc->vx = (float)atof(Token);
00151 break;
00152 case 6:
00153 Proc->vy = (float)atof(Token);
00154 break;
00155 case 7:
00156 Proc->vz = (float)atof(Token);
00157 break;
00158 }
00159
00160 TokenNum++;
00161
00162 if (TokenNum >= 8)
00163 break;
00164
00165 Token = strtok(NULL," \t,+\n\r");
00166
00167 }
00168
00169 }
00170
00171 if (!Smoke_InitBitmap(Proc, Bitmap))
00172 goto ExitWithError;
00173
00174 if (Proc->x < 0.0f)
00175 Proc->x = 0.0f;
00176 if (Proc->x > Proc->Width-1)
00177 Proc->x = (float)Proc->Width-1;
00178 if (Proc->y < 0.0f)
00179 Proc->x = 0.0f;
00180 if (Proc->y > Proc->Height-1)
00181 Proc->y = (float)Proc->Height-1;
00182
00183 if (!Smoke_Animate(Proc, 0.1f))
00184 {
00185 goto ExitWithError;
00186 }
00187
00188 return Proc;
00189
00190 ExitWithError:
00191 {
00192 if (Proc)
00193 Smoke_Destroy(Proc);
00194
00195 return NULL;
00196 }
00197 }
00198
00199
00200
00201
00202 void Smoke_Destroy(Procedural *Proc)
00203 {
00204 assert(Proc);
00205
00206 if (Proc->ZBuffer)
00207 {
00208 geRam_Free(Proc->ZBuffer);
00209 Proc->ZBuffer = NULL;
00210 }
00211
00212 if (Proc->ZAge)
00213 {
00214 geRam_Free(Proc->ZAge);
00215 Proc->ZAge = NULL;
00216 }
00217
00218 if (Proc->Bitmap)
00219 {
00220 geBitmap_Destroy(&Proc->Bitmap);
00221 Proc->Bitmap = NULL;
00222 }
00223
00224 geRam_Free(Proc);
00225 }
00226
00227
00228
00229
00230 geBoolean Smoke_Animate(Procedural *Smoke, float ElapsedTime)
00231 {
00232 if (!Smoke->Bitmap)
00233 return GE_TRUE;
00234
00235 if (!Smoke_Update(Smoke, Smoke->NumParticles, Smoke->x, Smoke->y, Smoke->z, Smoke->vx, Smoke->vy, Smoke->vz, 1))
00236 return GE_FALSE;
00237
00238 return GE_TRUE;
00239 }
00240
00241
00242
00243 static Procedural_Table Smoke_Table =
00244 {
00245 Procedurals_Version,Procedurals_Tag,
00246 "Smoke",
00247 Smoke_Create,
00248 Smoke_Destroy,
00249 Smoke_Animate
00250 };
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 Procedural_Table *Smoke_GetProcedural_Table(void)
00264 {
00265 return &Smoke_Table;
00266 }
00267
00268
00269
00270
00271
00272 void Smoke_FillParticle(Smoke_Data *particle,
00273 float xp,
00274 float yp,
00275 float zp,
00276 float xv,
00277 float yv,
00278 float zv)
00279 {
00280 int tmp;
00281
00282 particle->Position[0] = (int32)((xp * 0x10000) + ((rand()&1) ? (rand() * xp) : (-rand() * xp)));
00283
00284 tmp = rand() << 3;
00285 if(rand() & 1)
00286 tmp = -tmp;
00287
00288 particle->Position[1] = (int32)(yp * 0x10000) + tmp;
00289
00290 tmp = rand() << 1;
00291 if(rand() & 1)
00292 tmp = -tmp;
00293
00294 particle->Position[2] = (int32)(zp * 0x10000) + tmp;
00295
00296 tmp = rand() << 1;
00297 if(rand() & 1)
00298 tmp = -tmp;
00299 particle->Velocity[0] = (int32)(xv * 0x10000) + tmp;
00300
00301
00302
00303 particle->Velocity[1] = (int32)(yv * rand() );
00304 if(rand() & 1)
00305 particle->Velocity[1] = -particle->Velocity[1];
00306 particle->Velocity[2] = (int32)(zv * (rand() << 1));
00307 if(rand() & 1)
00308 particle->Velocity[2] = -particle->Velocity[2];
00309 }
00310
00311
00312
00313
00314 geBoolean Smoke_Shade(Procedural *Smoke)
00315 {
00316 int32 *ZBuffer;
00317 float *ZAge;
00318 uint8 *Bits;
00319 int i;
00320
00321 geBitmap *Lock;
00322
00323 if (!geBitmap_LockForWriteFormat(Smoke->Bitmap, &Lock, 0, 0, GE_PIXELFORMAT_8BIT_PAL))
00324 goto Fail;
00325
00326 if (!geBitmap_GetInfo(Lock, &(Smoke->BitmapInfo),NULL) )
00327 goto Fail;
00328
00329 if (Smoke->BitmapInfo.Format != GE_PIXELFORMAT_8BIT_PAL )
00330 goto Fail;
00331
00332 Bits = geBitmap_GetBits(Lock);
00333 ZBuffer = Smoke->ZBuffer;
00334 ZAge = Smoke->ZAge;
00335
00336
00337
00338 for(i=0;i != Smoke->Size-5; i++, ZBuffer++, ZAge++)
00339 {
00340 int32 Result;
00341 int32 Val;
00342
00343 if(*ZBuffer == 0)
00344 continue;
00345
00346 Val = *ZBuffer;
00347
00348 Result = Val - *(ZBuffer-1);
00349 Result >>= 16;
00350
00351 Result += 128;
00352
00353 if(Result > 255)
00354 Result = 255;
00355 else if(Result < 0)
00356 Result = 0;
00357
00358
00359 Result *= (int32)*ZAge;
00360
00361 Bits[i] = min(Result + Bits[i], 255);
00362
00363 if(Val > ZBuffer[1])
00364 Bits[i+1] = max(Bits[i+1]-3,0);
00365 if(Val > ZBuffer[2])
00366 Bits[i+1] = max(Bits[i+2]-7,0);
00367 if(Val > ZBuffer[3])
00368 Bits[i+3] = max(Bits[i+3]-10,0);
00369 if(Val > ZBuffer[4])
00370 Bits[i+4] = max(Bits[i+4]-15,0);
00371 if(Val > ZBuffer[5])
00372 Bits[i+5] = max(Bits[i+5]-7,0);
00373 }
00374
00375
00376 for(i=0;i<2;i++)
00377 {
00378 geBitmapUtil_SmoothBits(&Smoke->BitmapInfo, Bits, Bits, 1, SMOOTH_WRAP);
00379 }
00380
00381 if (!geBitmap_UnLock(Lock))
00382 goto Fail;
00383
00384 return GE_TRUE;
00385
00386 Fail:
00387 {
00388 if (Lock )
00389 geBitmap_UnLock(Lock);
00390
00391 return GE_FALSE;
00392 }
00393 }
00394
00395
00396
00397 geBoolean Smoke_Update( Procedural *Smoke,
00398 int nparticles,
00399 float xp,
00400 float yp,
00401 float zp,
00402 float xv,
00403 float yv,
00404 float zv,
00405 int lightdir)
00406 {
00407 int32 *ZBuffer;
00408 float *ZAge;
00409 Smoke_Data *Smbuf;
00410 int32 i;
00411
00412 ZBuffer = Smoke->ZBuffer;
00413 ZAge = Smoke->ZAge;
00414 Smbuf = Smoke->Smbuf;
00415
00416
00417 memset(ZBuffer,0, Smoke->Size*sizeof(int32));
00418 memset(ZAge,0, Smoke->Size*sizeof(float));
00419
00420
00421
00422 for(i=0;i<nparticles;i++)
00423 {
00424 int x,y;
00425
00426 if(Smbuf[i].Velocity[0] < 0x1000)
00427 {
00428
00429 Smoke_FillParticle(&Smbuf[i],xp,yp,zp,xv,yv,zv);
00430 continue;
00431 }
00432
00433 Smbuf[i].Position[0] += Smbuf[i].Velocity[0];
00434 Smbuf[i].Position[1] += Smbuf[i].Velocity[1];
00435 Smbuf[i].Position[2] += Smbuf[i].Velocity[2];
00436
00437
00438 Smbuf[i].Velocity[0] -= (Smbuf[i].Velocity[0] >> 5);
00439 Smbuf[i].Velocity[1] -= (Smbuf[i].Velocity[1] >> 5);
00440 Smbuf[i].Velocity[1] -= 0x800;
00441 Smbuf[i].Velocity[2] -= (Smbuf[i].Velocity[2] >> 5);
00442
00443
00444 if((Smbuf[i].Position[0]>>16) > (Smoke->Width-1))
00445 Smoke_FillParticle(&(Smbuf[i]),xp,yp,zp,xv,yv,zv);
00446 else if ((Smbuf[i].Position[0]>>16) < 0)
00447 Smoke_FillParticle(&(Smbuf[i]),xp,yp,zp,xv,yv,zv);
00448 else if((Smbuf[i].Position[1]>>16) > (Smoke->Height-1) || (Smbuf[i].Position[1]>>16) < 0)
00449 Smoke_FillParticle((&Smbuf[i]),xp,yp,zp,xv,yv,zv);
00450
00451
00452
00453
00454 x = Smbuf[i].Position[0] >> 16;
00455 y = Smbuf[i].Position[1] >> 16;
00456
00457
00458 if(Smbuf[i].Position[2] > ZBuffer[(y*Smoke->Width) + x])
00459 {
00460 ZBuffer[(y*Smoke->Width) + x] = Smbuf[i].Position[2];
00461 ZAge[(y*Smoke->Width) + x] = Smbuf[i].Velocity[0] * (2.5f / 0x30000);
00462 }
00463 }
00464
00465
00466 if (!Smoke_Shade(Smoke))
00467 return GE_FALSE;
00468
00469 return GE_TRUE;
00470 }
00471
00472 typedef struct
00473 {
00474 float f, a, r, g, b;
00475 } CPoint;
00476
00477 static char PalStr[][256] = {
00478 "Smoke_PalSlime",
00479 "Smoke_PalFire",
00480 "Smoke_PalOrange",
00481 "Smoke_PalBlue",
00482 };
00483
00484 #define PalStrTableSize (sizeof(PalStr) / sizeof(char[256]))
00485
00486 static CPoint CPoints[PalStrTableSize][3] =
00487 {
00488 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
00489 30.0f, 70.0f, 0.0f, 30.0f, 0.0f,
00490 180.0f, 255.0f, 255.0f, 255.0f, 25.0f,
00491
00492 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
00493 30.0f, 70.0f, 40.0f, 0.0f, 0.0f,
00494 180.0f, 255.0f, 255.0f, 255.0f, 25.0f,
00495
00496 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
00497 30.0f, 70.0f, 70.0f, 10.0f, 0.0f,
00498 180.0f, 255.0f, 255.0f, 255.0f, 25.0f,
00499
00500 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
00501 30.0f, 60.0f, 5.0f, 5.0f, 30.0f,
00502 180.0f, 255.0f, 100.0f, 100.0f, 165.0f
00503 };
00504
00505 static uint16 Smoke_LerpColor(float c1, float c2, float Ratio)
00506 {
00507 float Val;
00508
00509 Val = c1+(c2 - c1)*Ratio;
00510
00511 Val *= 8.0f;
00512
00513 if (Val > 255.0f)
00514 Val = 255.0f;
00515
00516 return (uint16)Val;
00517 }
00518
00519
00520
00521
00522 int32 Smoke_GetPalIndexFromString(const char *Str)
00523 {
00524 int32 i;
00525
00526 for (i=0; i<PalStrTableSize; i++)
00527 {
00528 if (!stricmp(Str, PalStr[i]))
00529 return i;
00530 }
00531
00532 return 0;
00533 }
00534
00535
00536
00537
00538 geBoolean Smoke_InitBitmap(Procedural *Proc, geBitmap **ppBitmap)
00539 {
00540 assert( ppBitmap);
00541
00542 if ( ! *ppBitmap )
00543 {
00544 *ppBitmap = geBitmap_Create(128, 128, 1, GE_PIXELFORMAT_8BIT_PAL);
00545
00546 if ( ! *ppBitmap )
00547 return GE_FALSE;
00548 }
00549 else
00550 {
00551 geBitmap_CreateRef(*ppBitmap);
00552 geBitmap_SetColorKey(*ppBitmap,GE_FALSE,0,0);
00553 }
00554
00555 if (!geBitmap_SetFormat(*ppBitmap,GE_PIXELFORMAT_8BIT_PAL,GE_FALSE,0,NULL) )
00556 return GE_FALSE;
00557
00558 if (!geBitmap_ClearMips(*ppBitmap) )
00559 return GE_FALSE;
00560
00561 if (!geBitmap_SetPreferredFormat(*ppBitmap,GE_PIXELFORMAT_16BIT_4444_ARGB) )
00562 return GE_FALSE;
00563
00564 if (!geBitmapUtil_SetColor(*ppBitmap,0,0,0,0) )
00565 return GE_FALSE;
00566
00567 if (!geBitmap_GetInfo(*ppBitmap, &Proc->BitmapInfo, NULL))
00568 return GE_FALSE;
00569
00570 Proc->Bitmap = *ppBitmap;
00571
00572 if (!Smoke_InitPalette(Proc))
00573 return GE_FALSE;
00574
00575 Proc->Width = Proc->BitmapInfo.Width;
00576 Proc->Height = Proc->BitmapInfo.Height;
00577 Proc->Size = Proc->Width*Proc->Height;
00578
00579 Proc->ZBuffer = GE_RAM_ALLOCATE_ARRAY(int32, Proc->Size);
00580
00581 if (!Proc->ZBuffer)
00582 goto ExitWithError;
00583
00584 Proc->ZAge = GE_RAM_ALLOCATE_ARRAY(float, Proc->Size);
00585
00586 if (!Proc->ZAge)
00587 goto ExitWithError;
00588
00589
00590 memset(Proc->ZBuffer,0, Proc->Size*sizeof(int32));
00591 memset(Proc->ZAge,0, Proc->Size*sizeof(float));
00592 memset(Proc->Smbuf, 0, NSMPARTICLES*sizeof(Smoke_Data));
00593
00594 return GE_TRUE;
00595
00596 ExitWithError:
00597 {
00598 if (Proc->ZBuffer)
00599 {
00600 geRam_Free(Proc->ZBuffer);
00601 Proc->ZBuffer = NULL;
00602 }
00603
00604 if (Proc->ZAge)
00605 {
00606 geRam_Free(Proc->ZAge);
00607 Proc->ZAge = NULL;
00608 }
00609 }
00610
00611 return GE_FALSE;
00612 }
00613
00614
00615
00616 geBoolean Smoke_InitPalette(Procedural *Proc)
00617 {
00618 geBitmap_Info Info;
00619 geBitmap_Palette *Pal;
00620 void *PalData = NULL;
00621 gePixelFormat PalFormat;
00622 int PalSize;
00623
00624 Pal = geBitmap_Palette_Create(GE_PIXELFORMAT_32BIT_ARGB,256);
00625 if ( ! Pal )
00626 goto fail;
00627 if ( ! geBitmap_SetPalette(Proc->Bitmap,Pal) )
00628 goto fail;
00629 geBitmap_Palette_Destroy(&Pal);
00630
00631 if (!geBitmap_GetInfo(Proc->Bitmap,&Info,NULL) )
00632 goto fail;
00633
00634 if (Info.Format != GE_PIXELFORMAT_8BIT_PAL )
00635 goto fail;
00636
00637 if (!(Pal = geBitmap_GetPalette(Proc->Bitmap)) )
00638 goto fail;
00639
00640 if (!geBitmap_Palette_Lock(Pal,&PalData, &PalFormat, &PalSize) )
00641 goto fail;
00642 if ( PalSize < 256 )
00643 goto fail;
00644
00645 {
00646 int32 i;
00647 int32 NumControlPoints, Current;
00648 CPoint *pPoint;
00649
00650
00651 NumControlPoints = 3;
00652
00653 Current = 0;
00654
00655 pPoint = &CPoints[Proc->PalIndex][0];
00656
00657 for (i=0; i<256; i++)
00658 {
00659 float Ratio;
00660 int32 Next;
00661 uint32 R,G,B,A;
00662 uint8 *PalPtr;
00663
00664 Next = Current+1;
00665
00666 if (Next > NumControlPoints-1)
00667 Next = NumControlPoints-1;
00668
00669 Ratio = (float)(i-pPoint[Current].f)/pPoint[Next].f;
00670
00671 if (Ratio > 1.0f)
00672 Ratio = 1.0f;
00673 else if (Ratio < 0.0f)
00674 Ratio = 0.0f;
00675
00676 PalPtr = ((uint8 *)PalData) + i * gePixelFormat_BytesPerPel(PalFormat);
00677
00678 A = (uint32)Smoke_LerpColor(pPoint[Current].a, pPoint[Next].a, Ratio);
00679 R = (uint32)Smoke_LerpColor(pPoint[Current].r, pPoint[Next].r, Ratio);
00680 G = (uint32)Smoke_LerpColor(pPoint[Current].g, pPoint[Next].g, Ratio);
00681 B = (uint32)Smoke_LerpColor(pPoint[Current].b, pPoint[Next].b, Ratio);
00682
00683 gePixelFormat_PutColor(PalFormat,&PalPtr,R,G,B,A);
00684
00685 if ((float)i >= pPoint[Next].f)
00686 {
00687 Current++;
00688
00689 if (Current > NumControlPoints-1)
00690 Current = NumControlPoints-1;
00691 }
00692 }
00693 }
00694
00695 PalData = NULL;
00696
00697 if ( ! geBitmap_Palette_UnLock(Pal) )
00698 return GE_FALSE;
00699
00700 return GE_TRUE;
00701
00702 fail:
00703
00704 if ( PalData )
00705 geBitmap_Palette_UnLock(Pal);
00706
00707 return GE_FALSE;
00708
00709 }